home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / rpg / crossfir.92 / crossfir / crossfire-0.92.5 / server / player.c < prev    next >
C/C++ Source or Header  |  1996-07-24  |  76KB  |  2,664 lines

  1. /*
  2.  * static char *rcsid_player_c =
  3.  *   "$Id: player.c,v 1.56 1996/07/24 07:40:18 master Exp master $";
  4.  */
  5.  
  6. /*
  7.     CrossFire, A Multiplayer game for X-windows
  8.  
  9.     Copyright (C) 1994 Mark Wedel
  10.     Copyright (C) 1992 Frank Tore Johansen
  11.  
  12.     This program is free software; you can redistribute it and/or modify
  13.     it under the terms of the GNU General Public License as published by
  14.     the Free Software Foundation; either version 2 of the License, or
  15.     (at your option) any later version.
  16.  
  17.     This program is distributed in the hope that it will be useful,
  18.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.     GNU General Public License for more details.
  21.  
  22.     You should have received a copy of the GNU General Public License
  23.     along with this program; if not, write to the Free Software
  24.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25.  
  26.     The author can be reached via e-mail to master@rahul.net
  27. */
  28.  
  29. #include <pwd.h>
  30. #include <global.h>
  31. #ifndef __CEXTRACT__
  32. #include <sproto.h>
  33. #endif
  34. #include <player.h>
  35. #include <sounds.h>
  36. #include <living.h>
  37. #include <object.h>
  38. #include <spells.h>
  39. #include <skills.h>
  40. #include <newclient.h>
  41.  
  42. /* This function returns TRUE if the object should be shown in the
  43.  * inventory window (due to show_what flags and object status).  This
  44.  * should be a macro.
  45.  * By putting this in a function, it makes it easier to add new display
  46.  * types, and eliminates repetitive code.
  47.  *
  48.  * This function will only be used in the new client once all the
  49.  * old X11 stuff in the server is removed.
  50.  */
  51.  
  52. int show_what_object(object *tmp, int show_what)
  53. {
  54.     if (tmp->invisible) return 0;
  55.     switch (show_what) {
  56.     case show_all:
  57.         return 1;
  58.  
  59.     case show_applied:
  60.         if (QUERY_FLAG(tmp, FLAG_APPLIED)) return 1;
  61.         else return 0;
  62.  
  63.     case show_unapplied:
  64.         if (QUERY_FLAG(tmp, FLAG_APPLIED)) return 0;
  65.         else return 1;
  66.  
  67.     case show_unpaid:
  68.         if (QUERY_FLAG(tmp, FLAG_UNPAID)) return 1;
  69.         else return 0;
  70.  
  71.     case show_cursed:
  72.         if (QUERY_FLAG(tmp, FLAG_KNOWN_CURSED)) return 1;
  73.         else return 0;
  74.  
  75.     case show_magical:
  76.     case show_nonmagical: {
  77.         int status = QUERY_FLAG(tmp, FLAG_KNOWN_MAGICAL) ||
  78.         (QUERY_FLAG(tmp, FLAG_IDENTIFIED) && is_magical(tmp));
  79.  
  80.         return (show_what==show_magical? status : !status);
  81.     }
  82.     default:
  83.         LOG(llevError,"show_what_object: unknown show_what state: %d\n",
  84.         show_what);
  85.     }
  86.     return 0;
  87. }
  88.  
  89. void display_motd(object *op) {
  90. #ifdef MOTD
  91.   char buf[MAX_BUF];
  92.   FILE *fp;
  93.   int comp;
  94.  
  95.   sprintf(buf,"%s/%s",LibDir,MOTD);
  96.   if((fp=open_and_uncompress(buf,0,&comp))==NULL) {
  97.     return;
  98.   }
  99.   while(fgets(buf,MAX_BUF,fp)!=NULL) {
  100.     char *cp;
  101.     if(*buf=='#')
  102.       continue;
  103.     cp=strchr(buf,'\n');
  104.     if(cp!=NULL)
  105.       *cp='\0';
  106.     new_draw_info(NDI_UNIQUE, 0,op,buf);
  107.   }
  108.   close_and_delete(fp, comp);
  109.   new_draw_info(NDI_UNIQUE, 0,op," ");
  110. #endif
  111. }
  112.  
  113. int playername_ok(char *cp) {
  114.   for(;*cp!='\0';cp++)
  115.     if(!((*cp>='a'&&*cp<='z')||(*cp>='A'&&*cp<='Z'))&&*cp!='-'&&*cp!='_')
  116.       return 0;
  117.   return 1;
  118. }
  119.  
  120. int add_player(char *disp, char *username, mapstruct *m, int esrv_client) {
  121.   player *p;
  122.   char buf[MAX_BUF],*cp,*defname = "nobody";
  123.   struct passwd *pwent;
  124.  
  125.   if (username == NULL) {
  126.     pwent = getpwuid(getuid());
  127.     if (pwent)
  128.       username = pwent->pw_name;
  129.     else
  130.       username = defname;
  131.   }
  132.  
  133.   /* Check for banned players and sites */
  134.  
  135.   if (checkbanned (username, disp)){
  136.     fprintf (logfile, "Banned player tryed to add. [%s@%s]\n", username, disp);
  137.     fflush (logfile);
  138.     return 0;
  139.   }
  140.  
  141.  
  142.   init_beforeplay(); /* Make sure everything is ready */
  143.   if(m == NULL)
  144.     m = ready_map_name(first_map_path,0);
  145.   if(m == NULL)
  146.     fatal(MAP_ERROR);
  147.   m->timeout = MAP_TIMEOUT(m); /* Just in case we fail to add the player */
  148.   p=get_player_ob();
  149.   p->eric_server = esrv_client;
  150.  
  151.   p->name=add_string(disp);
  152.   p->username = strdup_local(username);
  153.   p->writing=0,
  154.   p->weapon_sp=0,p->last_weapon_sp= -1;
  155.   p->last_armour= (-1);
  156.   p->has_hit=0;
  157.   p->scroll_inv=0;
  158.   p->scroll_look=0;
  159.  
  160.   if (p->show_inv_icon)
  161.     strcpy(p->format_inv,"%-20.20s%-6s"); /* This can be changed by resize */
  162.   else
  163.     strcpy(p->format_inv,"%-24.24s%-6s"); /* This can be changed by resize */
  164.  
  165.   strcpy(p->format_look,"%-24.24s%-6s");
  166.   p->inv_size=INV_SIZE;
  167.   p->look_size=LOOK_SIZE;
  168.   p->inv_chars=30;
  169.   p->look_chars=30;
  170.   p->barlength_inv=BARLENGTH_INV;
  171.   p->barlength_look=BARLENGTH_LOOK;
  172.   p->last_scroll_inv=p->last_scroll_look=1,
  173.   p->scrollsize_inv= p->scrollsize_look= p->scrollsize_hp=p->scrollsize_sp=
  174.   p->scrollsize_food=p->scrollstart_inv= p->scrollsize_grace=p->scrollstart_look=0,
  175.   p->nrofdrawn_inv=0,p->nrofdrawn_look=0;
  176.   p->peaceful=1;            /* default peaceful */
  177.   p->do_los=1;
  178.   p->scroll=0;                /* default without scroll */
  179.   p->split_window=default_split_window;    /* See -w flag */
  180.   p->last_weight= -1;
  181.   p->freeze_inv=p->freeze_look=0;
  182.   p->viewmap=0;
  183.   p->mapres=1;
  184.   p->mapdelx[0]= -1;
  185. #ifdef EXPLORE_MODE
  186.   p->explore=0;
  187. #endif  
  188.   p->menu = NULL;
  189.   if(use_pixmaps)
  190.     p->use_pixmaps = 1;
  191.   if (color_pix) {
  192.     p->use_pixmaps = 1;
  193.     p->color_pixmaps = 1;
  194.   }
  195.   if (esrv_client>0) {
  196.     p->gdisp = NULL;
  197.     load_default_keys(p);
  198.     p->gdisp = NULL;
  199.   } else {
  200.     strncpy(buf,disp,MAX_BUF);
  201.     if(strchr(buf,':')==NULL)
  202.       strcat(buf,":0");
  203.     if(get_root_display(p,buf)  || get_game_display(p,buf) ||
  204.        get_stats_display(p,buf) || get_info_display(p,buf) ||
  205.        get_inv_display(p,buf)   || get_look_display(p,buf) ||
  206.        get_message_display(p,buf)) {
  207.       free_player(p);
  208.       return 1;
  209.     }
  210.  
  211.     setuperrors();
  212.     /* Is there any reason that the values checked for in the if statements
  213.      * need to be re-set below them?  MSW (master@rahul.net)
  214.      */
  215.     if (p->color_pixmaps) {
  216.     p->color_pixmaps = 1;
  217.     p->use_pixmaps = 1;
  218.     if (ReadPixmaps(p->gdisp, &p->pixmaps, &p->masks,&p->colormap)) {
  219.         if (!p->split_window)
  220.         XSetWindowColormap(p->gdisp, p->win_root, p->colormap);
  221.         XSetWindowColormap(p->gdisp, p->win_game, p->colormap);
  222.         XSetWindowColormap(p->gdisp, p->win_info, p->colormap);
  223.         XSetWindowColormap(p->gdisp, p->win_message, p->colormap);
  224.         XSetWindowColormap(p->gdisp, p->win_inv, p->colormap);
  225.         XSetWindowColormap(p->gdisp, p->win_look, p->colormap);
  226.     }
  227.     }
  228.     else if(p->use_pixmaps) {
  229.       p->use_pixmaps = 1;
  230.       p->pixmaps = ReadBitmaps (p->gdisp);
  231.     }
  232.  
  233.     load_default_keys(p);
  234.  
  235.     Protocol_atom = XInternAtom(p->gdisp, "WM_PROTOCOLS", False);
  236.     Kill_atom = XInternAtom(p->gdisp, "WM_DELETE_WINDOW", False);
  237.     if(!p->split_window)
  238.       XSetWMProtocols(p->gdisp, p->win_root, &Kill_atom, 1);
  239.     else { /* I hope this is correct... */
  240.       XSetWMProtocols(p->gdisp, p->win_game, &Kill_atom, 1);
  241.       XSetWMProtocols(p->gdisp, p->win_stats, &Kill_atom, 1);
  242.       XSetWMProtocols(p->gdisp, p->win_info, &Kill_atom, 1);
  243.       XSetWMProtocols(p->gdisp, p->win_inv, &Kill_atom, 1);
  244.       XSetWMProtocols(p->gdisp, p->win_look, &Kill_atom, 1);
  245.       XSetWMProtocols(p->gdisp, p->win_message, &Kill_atom, 1);
  246.     }
  247.   }
  248.   free_string(p->ob->name);
  249.   p->ob->name = NULL;
  250.   free_object(p->ob);
  251.   p->ob=get_player(p,m);
  252.   add_friendly_object(p->ob);
  253. #ifdef MOTD
  254.   display_motd(p->ob);
  255. #endif
  256.   if (esrv_client) {
  257.     /* These things get set below - set them here to default values for
  258.      * ericserver.
  259.      */
  260. #ifdef SOUND_EFFECTS
  261.     p->rplay_fd = 0;
  262. #endif
  263.     p->peaceful=0;
  264.     p->berzerk=0;
  265.     p->scroll=0;
  266.     p->own_title[0]='\0';
  267.     get_name(p->ob);
  268.   } else {
  269.     if ((cp = XGetDefault(p->gdisp, name, "wimpy")) != NULL)
  270.       p->ob->run_away = atoi(cp);
  271. #ifdef SOUND_EFFECTS
  272.     if ((cp = XGetDefault(p->gdisp, name, "sounds")) != NULL)
  273.       {
  274.     if (!strcmp("on", cp) || !strcmp("yes", cp))
  275.       p->rplay_fd = init_disp_sound(disp);
  276.     else if (!strcmp("off", cp) || !strcmp("no", cp))
  277.       p->rplay_fd = 0;
  278.       }
  279.     else
  280.       p->rplay_fd = init_disp_sound(disp);
  281.     LOG(llevDebug, "Rplay fd: %d\n", p->rplay_fd);
  282.     play_sound_player_only(p, SOUND_NEW_PLAYER);
  283. #endif
  284.  
  285.     if((cp=XGetDefault(p->gdisp,name,"name"))!=NULL&&check_name(p,cp)) {
  286.       if(p->ob->name!=NULL)
  287.     free_string(p->ob->name);
  288.       p->ob->name=add_string(cp);
  289.       remove_lock(p);
  290.       get_password(p->ob);
  291.       p->name_changed=1;
  292.     } else {
  293.       get_name(p->ob);
  294.       cp=strchr(buf,'.');
  295.       if(cp!=NULL) *cp='\0';
  296.       cp=strchr(buf,':');
  297.       if(cp!=NULL) *cp='\0';
  298.       p->ob->name=add_string(buf);
  299.       p->name_changed=0;
  300.     }
  301.     if((cp=XGetDefault(p->gdisp,name,"peaceful"))!=NULL)
  302.       if(!strcmp("on",cp)||!strcmp("yes",cp))
  303.     p->peaceful=1;
  304.       else if(!strcmp("off",cp)||!strcmp("no",cp))
  305.     p->peaceful=0;
  306.     if((cp=XGetDefault(p->gdisp,name,"berzerk"))!=NULL)
  307.       if(!strcmp("on",cp)||!strcmp("yes",cp))
  308.     p->berzerk=1;
  309.       else if(!strcmp("off",cp)||!strcmp("no",cp))
  310.     p->berzerk=0;
  311.     if((cp=XGetDefault(p->gdisp,name,"scroll"))!=NULL)
  312.       if(!strcmp("on",cp)||!strcmp("yes",cp))
  313.     p->scroll=1;
  314.       else if(!strcmp("off",cp)||!strcmp("no",cp))
  315.     p->scroll=0;
  316.     if((cp=XGetDefault(p->gdisp,name,"title"))!=NULL && strlen(cp)<MAX_NAME)
  317.     strcpy (p->own_title, cp);
  318.     else
  319.     p->own_title[0]='\0';
  320.   }
  321.   return 0;
  322. }
  323.  
  324. /*
  325.  * get_player_archetype() return next player archetype from archetype
  326.  * list. Not very efficient routine, but used only creating new players.
  327.  * Note: there MUST be at least one player archetype!
  328.  */
  329. archetype *get_player_archetype(archetype* at)
  330. {
  331.     archetype *start = at;
  332.     for (;;) {
  333.     if (at==NULL || at->next==NULL)
  334.         at=first_archetype;
  335.     else
  336.         at=at->next;
  337.     if(at->clone.type==PLAYER)
  338.         return at;
  339.     if (at == start) {
  340.         LOG (llevError, "No Player achetypes\n");
  341.         exit (-1);
  342.     }
  343.     }
  344. }
  345.  
  346.  
  347. object *get_player(player *p, mapstruct *m) {
  348.   object *op=arch_to_object(get_player_archetype(NULL));
  349.   int i;
  350.  
  351.   p->loading = NULL;
  352.   op->map=m;
  353.   if(m->in_memory != MAP_IN_MEMORY) {
  354.     p->loading = m;
  355.     p->new_x = 0;
  356.     p->new_y = 0;
  357.     p->removed = 0;
  358.     op->x=0;
  359.     op->y=0;
  360.   } else {
  361.     i=find_free_spot(NULL,m,EXIT_X(m->map_object),EXIT_Y(m->map_object),
  362.     0,SIZEOFFREE);
  363.     op->x=EXIT_X(m->map_object)+freearr_x[i];
  364.     op->y=EXIT_Y(m->map_object)+freearr_y[i];
  365.   }
  366.   p->fire_on=0,p->run_on=0;
  367.   p->count=0;
  368.   p->count_left=0;
  369.   p->prev_cmd=' ';
  370.   p->prev_fire_on=0;
  371.   p->mode=0;
  372.   p->berzerk=1;
  373.   p->idle=0;
  374. #ifdef AUTOSAVE
  375.   p->last_save_tick = 9999999;
  376. #endif
  377.   *p->maplevel=0;
  378.  
  379.   op->contr=p; /* this aren't yet in archetype */
  380.   op->speed_left=0.5;
  381.   op->speed=1.0;
  382.   op->direction=0;
  383.   op->stats.wc=2;
  384.   op->run_away = 25; /* Then we panick... */
  385.  
  386.   roll_stats(op);
  387.   p->state=ST_ROLL_STAT;
  388.   clear_los(op);
  389.   p->last_stats.Str=0,  p->last_stats.Dex=0,
  390.   p->last_stats.Int=0,  p->last_stats.Con=0,
  391.   p->last_stats.Wis=0,  p->last_stats.Cha=0;
  392.   p->last_stats.Pow=0,  p->last_stats.Pow=0;
  393.   p->last_stats.hp=0,   p->last_stats.maxhp=0;
  394.   p->last_stats.wc=0,   p->last_stats.ac=0;
  395.   p->last_stats.sp=0,   p->last_stats.maxsp=0;
  396.   p->last_stats.grace=0, p->last_stats.maxgrace=0;
  397.   p->last_stats.exp= -1,p->last_stats.food=0;
  398.   p->digestion=0,p->gen_hp=0,p->gen_sp=0,p->gen_grace=0;
  399.   p->last_spell= -1;
  400.   p->last_value= -1;
  401.   p->last_speed= -1;
  402.   p->shoottype=range_none,p->shootstrength=5;
  403.   p->last_shoot= range_bottom;
  404.   p->listening=9;
  405.   p->golem=NULL;
  406.   p->last_used=NULL;
  407.   p->last_used_id=0;
  408.   strncpy(p->title,op->arch->clone.name,MAX_NAME);
  409.   op->race = add_string (op->arch->clone.race);
  410.  
  411.   (void)memset((void *)op->contr->drawn,'\0',
  412.            sizeof(Fontindex)*(WINRIGHT-WINLEFT+1)*(WINLOWER-WINUPPER+1));
  413.   for(i=0;i<NROFREALSPELLS;i++)
  414.     p->known_spells[i]= -1;
  415.   p->nrofknownspells=0;
  416.   p->chosen_spell = -1;
  417.   p->ob->chosen_skill = NULL;
  418. #ifdef LINKED_SKILL_LIST
  419.   p->ob->sk_list = NULL;
  420. #endif
  421.   if(QUERY_FLAG(op,FLAG_READY_SKILL))
  422.         CLEAR_FLAG(op,FLAG_READY_SKILL); 
  423.   draw_all_inventory(op);
  424.   draw_all_look(op);
  425.   return op;
  426. }
  427.  
  428. object *get_nearest_player(object *mon) {
  429.   object *op = NULL;
  430.   objectlink *ol;
  431.   int lastdist,tmp;
  432.  
  433.   for(ol=first_friendly_object,lastdist=1000;ol!=NULL;ol=ol->next) {
  434.     if((ol->ob->type==PLAYER && ol->ob->contr->state)
  435.        ||((ol->ob->invisible&&QUERY_FLAG(ol->ob,FLAG_UNDEAD)==QUERY_FLAG(mon,FLAG_UNDEAD))
  436.       &&!QUERY_FLAG(mon,FLAG_SEE_INVISIBLE))||ol->ob->map!=mon->map)
  437.       continue;
  438.     tmp=distance(ol->ob,mon);
  439.     if(lastdist>tmp) {
  440.       op=ol->ob;
  441.       lastdist=tmp;
  442.     }
  443.   }
  444.   return op;
  445. }
  446.  
  447. int path_to_player(object *mon, object *pl,int mindiff) {
  448.   int dir,x,y,diff;
  449.   dir=find_dir_2(mon->x-pl->x,mon->y-pl->y);
  450.   x=mon->x+freearr_x[dir],y=mon->y+freearr_y[dir];
  451.   if(mon->value) x++;
  452.   diff=isqrt((x-pl->x)*(x-pl->x)+(y-pl->y)*(y-pl->y));
  453.   if(diff<mindiff) return 0;
  454.   while(diff-- > 0) {
  455.     if(blocked(mon->map,x,y))
  456.       return 0;
  457.     x+=freearr_x[dir],y+=freearr_y[dir];
  458.   }
  459.   return dir;
  460. }
  461.  
  462. void give_initial_items(object *pl) {
  463.   object *op,*next=NULL;
  464.   static uint8 start_spells[] = {0, 1, 4, 5, 7};
  465.   static uint8 start_prayers[] = {19, 31, 32, 129}; 
  466.   pl->contr->freeze_inv=1;
  467.   if(pl->arch->randomitems!=NULL)
  468.      create_treasure(pl->arch->randomitems,pl,GT_INVENTORY,1,0);
  469.  
  470.   op=pl->inv;
  471.   while(op || next) {
  472.     next = op->below;
  473.     if(op->nrof<2 && op->type!=CONTAINER && op->type!=MONEY)
  474.       SET_FLAG(op,FLAG_STARTEQUIP);
  475.     if(op->type==SPELLBOOK) { /* fix spells for first level spells */
  476.       if(!strcmp(op->arch->name,"cleric_book")) 
  477.            op->stats.sp=start_prayers[RANDOM()%(sizeof(start_prayers)/sizeof(uint8))];
  478.       else
  479.            op->stats.sp=start_spells[RANDOM()%sizeof(start_spells)];
  480.     }
  481.     /* Give starting characters identified, uncursed, and undamned
  482.      * items.  Just don't identify gold or silver, or it won't be
  483.      * merged properly.
  484.      */
  485.     if (need_identify(op)) {
  486.     SET_FLAG(op, FLAG_IDENTIFIED);
  487.     CLEAR_FLAG(op, FLAG_CURSED);
  488.     CLEAR_FLAG(op, FLAG_DAMNED);
  489.     }
  490. #ifndef ALLOW_SKILLS    /* no reason to start with these if no skills exist! */ 
  491.     if(op->type==SKILLSCROLL || op->type==SKILL)  {
  492.     remove_ob(op);
  493.     free_object(op);
  494.     }
  495. #endif
  496.     if(op->type==ABILITY)  {
  497.       pl->contr->known_spells[pl->contr->nrofknownspells++]=op->stats.sp;
  498.       remove_ob(op);
  499.       free_object(op);
  500.       }
  501.     op = next;
  502.   }
  503.   pl->contr->freeze_inv=0;
  504. }
  505.  
  506. void get_name(object *op) {
  507.   op->contr->write_buf[0]='\0';
  508.   op->contr->writing=0;
  509.   op->contr->state=ST_GET_NAME;
  510.   new_draw_info(NDI_UNIQUE, 0,op,"What is your name?");
  511.   if (op->contr->eric_server>0)
  512.     send_query(op->contr->eric_server,0,":");
  513.   else
  514.     write_ch(op,':');
  515. }
  516.  
  517. void get_password(object *op) {
  518.   op->contr->write_buf[0]='\0';
  519.   op->contr->writing=0;
  520.   op->contr->state=ST_GET_PASSWORD;
  521.   new_draw_info(NDI_UNIQUE, 0,op,"What is your password?");
  522.   if (op->contr->eric_server>0)
  523.     send_query(op->contr->eric_server,CS_QUERY_HIDEINPUT, ":");
  524.   else {
  525.     write_ch(op,':');
  526.     op->contr->no_echo=1;
  527.   }
  528. }
  529.  
  530. void play_again(object *op)
  531. {
  532.      new_draw_info(NDI_UNIQUE, 0,op,"Do you want to play again (a/q)?");
  533.      op->contr->state=ST_PLAY_AGAIN;
  534.      remove_lock(op->contr);
  535.      if (op->contr->eric_server>0)
  536.     send_query(op->contr->eric_server, CS_QUERY_SINGLECHAR, "");
  537. }
  538.  
  539. void confirm_password(object *op) {
  540.  
  541.   op->contr->write_buf[0]='\0';
  542.   op->contr->writing=0;
  543.   op->contr->state=ST_CONFIRM_PASSWORD;
  544.   new_draw_info(NDI_UNIQUE, 0,op,"Please type your password again.");
  545.   if (op->contr->eric_server>0)
  546.     send_query(op->contr->eric_server, CS_QUERY_HIDEINPUT, ":");
  547.   else
  548.     write_ch(op,':');
  549.   op->contr->no_echo=1;
  550. }
  551.  
  552. #ifdef SIMPLE_PARTY_SYSTEM
  553. void get_party_password(object *op, int partyid) {
  554.   op->contr->write_buf[0]='\0';
  555.   op->contr->writing=0;
  556.   op->contr->state=ST_GET_PARTY_PASSWORD;
  557.   op->contr->party_number_to_join = partyid;
  558.   new_draw_info(NDI_UNIQUE, 0,op,"What is the password?");
  559.   if (op->contr->eric_server>0)
  560.     send_query(op->contr->eric_server, CS_QUERY_HIDEINPUT, ":");
  561.   else
  562.     write_ch(op,':');
  563. }
  564. #endif /* SIMPLE_PARTY_SYSTEM */
  565.  
  566. int roll_stat() {
  567.   int a[4],i,j,k;
  568.   for(i=0;i<4;i++)
  569.     a[i]=(int)RANDOM()%6+1;
  570.   for(i=0,j=0,k=7;i<4;i++)
  571.     if(a[i]<k)
  572.       k=a[i],j=i;
  573.   for(i=0,k=0;i<4;i++) {
  574.     if(i!=j)
  575.       k+=a[i];
  576.   }
  577.   return k;
  578. }
  579.  
  580. void roll_stats(object *op) {
  581.   int sum=0;
  582.   do {
  583.     op->stats.Str=roll_stat();
  584.     op->stats.Dex=roll_stat();
  585.     op->stats.Int=roll_stat();
  586.     op->stats.Con=roll_stat();
  587.     op->stats.Wis=roll_stat();
  588.     op->stats.Pow=roll_stat();
  589.     op->stats.Cha=roll_stat();
  590.     sum=op->stats.Str+op->stats.Dex+op->stats.Int+
  591.     op->stats.Con+op->stats.Wis+op->stats.Pow+
  592.     op->stats.Cha;
  593.   } while(sum<82||sum>116);
  594. #if defined( USE_SWAP_STATS) && defined(SORT_ROLLED_STATS)
  595.     /* Sort the stats so that rerolling is easier... */
  596.     {
  597.             int             i = 0, j = 0;
  598.             int             statsort[7];
  599.  
  600.             statsort[0] = op->stats.Str;
  601.             statsort[1] = op->stats.Dex;
  602.             statsort[2] = op->stats.Int;
  603.             statsort[3] = op->stats.Con;
  604.             statsort[4] = op->stats.Wis;
  605.             statsort[5] = op->stats.Pow;
  606.             statsort[6] = op->stats.Cha;
  607.  
  608.             /* a quick and dirty bubblesort? */
  609.             do {
  610.                     if (statsort[i] < statsort[i + 1]) {
  611.                             j = statsort[i];
  612.                             statsort[i] = statsort[i + 1];
  613.                             statsort[i + 1] = j;
  614.                             i = 0;
  615.                   } else {
  616.                             i++;
  617.                   }
  618.           } while (i < 6);
  619.  
  620.             op->stats.Str = statsort[0];
  621.             op->stats.Dex = statsort[1];
  622.             op->stats.Con = statsort[2];
  623.             op->stats.Int = statsort[3];
  624.             op->stats.Wis = statsort[4];
  625.             op->stats.Pow = statsort[5];
  626.             op->stats.Cha = statsort[6];
  627.       }
  628. #endif /* SWAP_STATS */
  629.  
  630. #if 1
  631.   op->contr->orig_stats.Str=op->stats.Str;
  632.   op->contr->orig_stats.Dex=op->stats.Dex;
  633.   op->contr->orig_stats.Int=op->stats.Int;
  634.   op->contr->orig_stats.Con=op->stats.Con;
  635.   op->contr->orig_stats.Wis=op->stats.Wis;
  636.   op->contr->orig_stats.Pow=op->stats.Pow;
  637.   op->contr->orig_stats.Cha=op->stats.Cha;
  638. #endif
  639.   op->stats.hp= -10000;
  640.   op->level=0;
  641.   op->stats.exp=0;
  642.   op->stats.sp=0;
  643.   op->stats.grace=0;
  644.   op->stats.ac=0;
  645.   add_exp(op,0);
  646.   op->stats.sp=op->stats.maxsp;
  647.   op->stats.hp=op->stats.maxhp;
  648. #ifndef ALLOW_SKILLS /* start grace at maxgrace if no skills */
  649.   op->stats.grace=op->stats.maxgrace; 
  650. #else
  651.   op->stats.grace=0;
  652. #endif
  653.   op->contr->orig_stats=op->stats;
  654. }
  655.  
  656. void Roll_Again(object *op)
  657. {
  658. #ifndef USE_SWAP_STATS
  659.   new_draw_info(NDI_UNIQUE, 0,op,"Roll again (y/n)? ");
  660. #else
  661.   new_draw_info(NDI_UNIQUE, 0,op,"[y] to roll new stats [n] to use stats");
  662.   new_draw_info(NDI_UNIQUE, 0,op,"[1-7] [1-7] to swap stats.\n");
  663.   new_draw_info(NDI_UNIQUE, 0,op,"Roll again (y/n/1-7)? ");
  664. #endif /* USE_SWAP_STATS */
  665.   if (op->contr->eric_server>0)
  666.     send_query(op->contr->eric_server,CS_QUERY_SINGLECHAR,"");
  667.  
  668. }
  669.  
  670. void Swap_Stat(object *op,int Swap_Second)
  671. {
  672. #ifdef USE_SWAP_STATS
  673.   signed char tmp;
  674.   char buf[MAX_BUF];
  675.  
  676.     if ( op->contr->Swap_First == -1 ) {
  677.     new_draw_info(NDI_UNIQUE, 0,op,"How the hell did you get here?!?!!!");
  678.     new_draw_info(NDI_UNIQUE, 0,op,"Error in Swap_Stat code,");
  679.     new_draw_info(NDI_UNIQUE, 0,op,"mail korg@rdt.monash.edu.au");
  680.     return;
  681.     }
  682.  
  683.     tmp = get_attr_value(&op->contr->orig_stats, op->contr->Swap_First);
  684.  
  685.     set_attr_value(&op->contr->orig_stats, op->contr->Swap_First,
  686.     get_attr_value(&op->contr->orig_stats, Swap_Second));
  687.  
  688.     set_attr_value(&op->contr->orig_stats, Swap_Second, tmp);
  689.  
  690.     sprintf(buf,"%s done\n", short_stat_name[Swap_Second]);
  691.     new_draw_info(NDI_UNIQUE, 0,op, buf);
  692.     op->stats.Str = op->contr->orig_stats.Str;
  693.     op->stats.Dex = op->contr->orig_stats.Dex;
  694.     op->stats.Con = op->contr->orig_stats.Con;
  695.     op->stats.Int = op->contr->orig_stats.Int;
  696.     op->stats.Wis = op->contr->orig_stats.Wis;
  697.     op->stats.Pow = op->contr->orig_stats.Pow;
  698.     op->stats.Cha = op->contr->orig_stats.Cha;
  699.     op->stats.hp= -10000;
  700.     op->level=0;
  701.     op->stats.exp=0;
  702.     op->stats.sp=0;
  703.     op->stats.grace=0;
  704.     op->stats.ac=0;
  705.     add_exp(op,0);
  706.     op->stats.sp=op->stats.maxsp;
  707. #ifndef ALLOW_SKILLS
  708.     op->stats.grace=op->stats.maxgrace; 
  709. #else
  710.     op->stats.grace=0;
  711. #endif
  712.     op->stats.hp=op->stats.maxhp;
  713.     add_exp(op,0);
  714.     op->contr->Swap_First=-1;
  715. #endif /* USE_SWAP_STATS */
  716. }
  717.  
  718.  
  719. /* This code has been greatly reduced, because with set_attr_value
  720.  * and get_attr_value, the stats can be accessed just numeric
  721.  * ids.  stat_trans is a table that translate the number entered
  722.  * into the actual stat.  It is needed because the order the stats
  723.  * are displayed in the stat window is not the same as how
  724.  * the number's access that stat.  The table does that translation.
  725.  */
  726. int key_roll_stat(object *op, char key)
  727. {
  728.     int keynum = key -'0';
  729.     char buf[MAX_BUF];
  730.     static sint8 stat_trans[] = {-1, STR, DEX, CON, INT, WIS, POW, CHA};
  731.  
  732. #ifdef USE_SWAP_STATS
  733.     if (keynum>0 && keynum<=7) {
  734.     if (op->contr->Swap_First==-1) {
  735.         op->contr->Swap_First=stat_trans[keynum];
  736.         sprintf(buf,"%s ->", short_stat_name[stat_trans[keynum]]);
  737.         new_draw_info(NDI_UNIQUE, 0,op,buf);
  738.     }
  739.     else
  740.         Swap_Stat(op,stat_trans[keynum]);
  741.  
  742.     if (op->contr->eric_server>0)
  743.         send_query(op->contr->eric_server,CS_QUERY_SINGLECHAR,"");
  744.     return 1;
  745.     }
  746. #endif
  747.     switch (key) {
  748.      case 'n':
  749.      case 'N':
  750.       SET_FLAG(op, FLAG_WIZ);
  751.       if(op->map==NULL) {
  752.     LOG(llevError,"Map == NULL in state 2\n");
  753.     break;
  754.       }
  755.       /* So that enter_exit will put us at startx/starty */
  756.       op->x= -1;
  757.       enter_exit(op,NULL);
  758.       /* Enter exit adds a player otherwise */
  759.       if(op->contr->loading == NULL) {
  760.     insert_ob_in_map(op,op->map);
  761.       }
  762.       else {
  763.     op->contr->removed = 0; /* Will insert pl. when map is loaded */
  764.       }
  765.       add_statbonus(op);
  766.       new_draw_info(NDI_UNIQUE, 0,op,"Now choose a character.");
  767.       new_draw_info(NDI_UNIQUE, 0,op,"Press any key to change outlook.");
  768.       new_draw_info(NDI_UNIQUE, 0,op,"Press `d' when you're pleased.");
  769.       op->contr->state = ST_CHANGE_CLASS;
  770.       if (op->contr->eric_server>0)
  771.       send_query(op->contr->eric_server,CS_QUERY_SINGLECHAR,"");
  772.       return 0;
  773.  
  774.      case 'y':
  775.      case 'Y':
  776.       roll_stats(op);
  777.       if (op->contr->eric_server>0)
  778.       send_query(op->contr->eric_server,CS_QUERY_SINGLECHAR,"");
  779.       return 1;
  780.  
  781.      case 'q':
  782.      case 'Q':
  783.       play_again(op);
  784.       return 1;
  785.  
  786.      default:
  787. #ifndef USE_SWAP_STATS
  788.       new_draw_info(NDI_UNIQUE, 0,op,"Yes, No or Quit. Roll again?");
  789. #else
  790.       new_draw_info(NDI_UNIQUE, 0,op,"Yes, No, Quit or 1-6.  Roll again?");
  791. #endif /* USE_SWAP_STATS */
  792.       if (op->contr->eric_server>0)
  793.       send_query(op->contr->eric_server,CS_QUERY_SINGLECHAR,"");
  794.       return 0;
  795.     }
  796.     return 0;
  797. }
  798.  
  799. /* This function takes the key that is passed, and does the
  800.  * appropriate action with it (change class, or other things.
  801.  */
  802.  
  803. int key_change_class(object *op, char key)
  804. {
  805.       int tmp_loop;
  806.  
  807.     if(key=='q'||key=='Q') {
  808.       remove_ob(op);
  809.       play_again(op);
  810.       return 0;
  811.     }
  812.     if(key=='d'||key=='D') {
  813.     /* this must before then initial items are given */
  814.     if (op->contr->eric_server > 0)
  815.       esrv_new_player(op->contr->eric_server, op->count, op->name, 
  816.         op->weight, op->face->number);
  817.     create_treasure(find_treasurelist("starting_wealth"),op, 0, 0, 0);
  818.  
  819.     op->contr->state=ST_PLAYING;
  820. #ifdef AUTOSAVE
  821.     op->contr->last_save_tick = pticks;
  822. #endif
  823.     start_info(op);
  824.     CLEAR_FLAG(op, FLAG_WIZ);
  825. #ifdef ALLOW_SKILLS
  826.     (void) init_player_exp(op);
  827. #endif
  828.     give_initial_items(op);
  829. #ifdef ALLOW_SKILLS
  830.     (void) link_player_skills(op);
  831. #endif
  832.     if (op->contr->eric_server > 0)
  833.       esrv_send_inventory(op, op);
  834.     else
  835.       draw_all_inventory(op);
  836.     return 0;
  837.     }
  838.  
  839.     /* Following actually changes the class - this is the default command
  840.      * if we don't match with one of the options above.
  841.      */
  842.  
  843.     tmp_loop = 0;
  844.     while(!tmp_loop) {
  845.       char *name = add_string (op->name);
  846.       int x = op->x, y = op->y;
  847.       remove_statbonus(op);
  848.       remove_ob (op);
  849.       op->arch = get_player_archetype(op->arch);
  850.       copy_object (&op->arch->clone, op);
  851.       op->stats = op->contr->orig_stats;
  852.       free_string (op->name);
  853.       op->name = name;
  854.       op->x = x;
  855.       op->y = y;
  856.       insert_ob_in_map (op, op->map);
  857.       strncpy(op->contr->title,op->arch->clone.name,MAX_NAME);
  858.       add_statbonus(op);
  859.       tmp_loop=allowed_class(op);
  860.     }
  861.     update_object(op);
  862.     fix_player(op);
  863.     op->stats.hp=op->stats.maxhp;
  864.     op->stats.sp=op->stats.maxsp;
  865. #ifndef ALLOW_SKILLS
  866.      op->stats.grace=op->stats.maxgrace; 
  867. #else
  868.      op->stats.grace=0;
  869. #endif
  870.     op->contr->last_value= -1;
  871.     draw_stats(op);
  872.     if (op->contr->eric_server>0)
  873.     send_query(op->contr->eric_server, CS_QUERY_SINGLECHAR,"");
  874.     return 0;
  875. }
  876.  
  877. int key_confirm_quit(object *op, char key)
  878. {
  879.     char buf[MAX_BUF];
  880.  
  881.     if(key!='y'&&key!='Y'&&key!='q'&&key!='Q') {
  882.       op->contr->state=ST_PLAYING;
  883.       new_draw_info(NDI_UNIQUE, 0,op,"OK, continuing to play.");
  884.       return 1;
  885.     }
  886.     terminate_all_pets(op);
  887.     remove_ob(op);
  888.     op->direction=0;
  889.     op->contr->count_left=0;
  890.     op->map->players--;
  891.     /* Just in case we fail to add the player */
  892.     op->map->timeout = MAP_TIMEOUT(op->map);
  893.     new_draw_info_format(NDI_UNIQUE | NDI_ALL, 5, NULL,
  894.     "%s quits the game.",op->name);
  895.  
  896.     strcpy(op->contr->killer,"quit");
  897.     check_score(op);
  898. #ifdef SIMPLE_PARTY_SYSTEM
  899.     op->contr->party_number=(-1);
  900. #endif /* SIMPLE_PARTY_SYSTEM */
  901. #ifdef SET_TITLE
  902.     op->contr->own_title[0]='\0';
  903. #endif /* SET_TITLE */
  904.     load_default_keys(op->contr);
  905.     if(!QUERY_FLAG(op,FLAG_WAS_WIZ)) {
  906.       sprintf(buf,"%s/%s/%s.pl",LibDir,PlayerDir,op->name);
  907.       if(unlink(buf)== -1 && debug)
  908.         perror("crossfire (delete character)");
  909.     }
  910.     play_again(op);
  911.     return 1;
  912. }
  913.  
  914.  
  915. void flee_player(object *op) {
  916.   int dir,diff;
  917.   if(op->stats.hp < 0) {
  918.     LOG(llevDebug, "Fleeing player is dead.\n");
  919.     CLEAR_FLAG(op, FLAG_SCARED);
  920.     return;
  921.   }
  922.   if(op->enemy==NULL) {
  923.     LOG(llevDebug,"Fleeing player had no enemy.\n");
  924.     CLEAR_FLAG(op, FLAG_SCARED);
  925.     return;
  926.   }
  927.   if(!(RANDOM()%5)&&RANDOM()%20+1>=savethrow[op->level]) {
  928.     op->enemy=NULL;
  929.     CLEAR_FLAG(op, FLAG_SCARED);
  930.     return;
  931.   }
  932.   dir=absdir(4+find_dir_2(op->x-op->enemy->x,op->y-op->enemy->y));
  933.   for(diff=0;diff<3;diff++) {
  934.     int m=1-(RANDOM()&2);
  935.     if(move_ob(op,absdir(dir+diff*m))||
  936.        (diff==0&&move_ob(op,absdir(dir-diff*m)))) {
  937.       draw(op);
  938.       return;
  939.     }
  940.   }
  941.   /* Cornered, get rid of scared */
  942.   CLEAR_FLAG(op, FLAG_SCARED);
  943.   op->enemy=NULL;
  944. }
  945.  
  946. int check_pick(object *op) {
  947.   int item_picked=0;        /* set to true if an item is picked up */
  948.  
  949.   if(QUERY_FLAG(op,FLAG_FLYING) || op->below==NULL || !can_pick(op,op->below))
  950.     return 1;
  951.  
  952. #ifdef SEARCH_ITEMS
  953.   if(op->contr->search_str[0]!='\0')
  954.     {
  955.       object *next,*tmp;
  956.       tmp=op->below;
  957.       while(tmp!=NULL&&can_pick(op,tmp))
  958.     {
  959.       next=tmp->below;
  960.       if(strstr(long_desc(tmp),op->contr->search_str)!=NULL) {
  961.         pick_up(op,tmp);
  962.         item_picked=1;
  963.       }
  964.       tmp=next;
  965.     }
  966.     }
  967. #endif /* SEARCH_ITEMS */
  968.  
  969.  
  970.   switch (op->contr->mode) {
  971.     case 0:    return 1;    /* don't pick up */
  972.  
  973.     case 1:
  974.         pick_up(op,op->below);
  975.         return 1;
  976.  
  977.     case 2:
  978.         pick_up(op,op->below);
  979.         return 0;
  980.  
  981.     case 3: return 0;    /* stop before pickup */
  982.  
  983.     case 4:
  984.     case 5: 
  985.     case 6:
  986.     case 7: {
  987.         object *item,*temp;
  988.  
  989.         item = op->below;
  990.         op->contr->freeze_inv=1;
  991.         while (item) {
  992.             temp = item->below;
  993.             if (can_pick(op, item)) {
  994.             if (op->contr->mode==6) {
  995.                 if (QUERY_FLAG(item, FLAG_KNOWN_MAGICAL) &&
  996.                   !QUERY_FLAG(item, FLAG_KNOWN_CURSED)) {
  997.                 pick_up(op, item);
  998.                 item_picked=1;
  999.                 }
  1000.             }
  1001.             else if (op->contr->mode==7) {
  1002.                 if (item->type==MONEY || item->type==GEM) {
  1003.                 item_picked=1;
  1004.                 pick_up(op, item);
  1005.                 }
  1006.             } else {
  1007.                 item_picked=1;
  1008.                 pick_up(op, item);
  1009.             }
  1010.             }
  1011.             item = temp;
  1012.         }
  1013.         op->contr->freeze_inv=0;
  1014.         if (item_picked && !op->contr->eric_server)
  1015.             draw_inventory(op);
  1016.         return (op->contr->mode != 4 ? 1 : 0);
  1017.     }
  1018.  
  1019.     /* use value density */
  1020.     default: {
  1021.         object * item,*temp;
  1022.  
  1023.         item=op->below;
  1024.         op->contr->freeze_inv=1;
  1025.         while(item) {
  1026.         temp=item->below;
  1027.         if(can_pick(op, item) && !(QUERY_FLAG(item, FLAG_UNPAID)) &&
  1028.          (query_cost(item,op,F_TRUE)*100/
  1029.             (item->weight * MAX(item->nrof,1))>= op->contr->mode) ) {
  1030.             item_picked=1;
  1031.             pick_up(op,item);
  1032.         }
  1033.         item=temp;
  1034.         }
  1035.         op->contr->freeze_inv=0;
  1036.         if (item_picked && !op->contr->eric_server)
  1037.         draw_inventory(op);
  1038.         return 1;
  1039.     }
  1040.  
  1041.   }
  1042.   return 1; /* Statement supposedly can't be reached */
  1043. }
  1044.  
  1045. /*
  1046.  *  Find an arrow in the inventory and after that
  1047.  *  in the right type container (quiver). Pointer to the 
  1048.  *  found object is returned.
  1049.  */
  1050. object *find_arrow(object *op, char *type)
  1051. {
  1052.   object *tmp = NULL;
  1053.  
  1054.   for(op=op->inv; op; op=op->below)
  1055.     if(!tmp && op->type==CONTAINER && op->race==type &&
  1056.       QUERY_FLAG(op,FLAG_APPLIED))
  1057.       tmp = find_arrow (op, type);
  1058.     else if (op->type==ARROW && op->race==type)
  1059.       return op;
  1060.   return tmp;
  1061. }
  1062.  
  1063. /*
  1064.  *  Player fires a bow. This probably should be combined with
  1065.  *  monster_use_bow().
  1066.  */
  1067. static void fire_bow(object *op, int dir)
  1068. {
  1069.   object *bow, *arrow = NULL, *left;
  1070.   for(bow=op->inv; bow; bow=bow->below)
  1071.     if(bow->type==BOW && QUERY_FLAG(bow, FLAG_APPLIED))
  1072.       break;
  1073. #ifdef MANY_CORES /* there must be applied bow if shoot_type is range_bow */
  1074.   if (!bow) {
  1075.     LOG (llevError, "Range: bow without activated bow.\n");
  1076.     abort();
  1077.   }
  1078. #endif
  1079.   if( !bow->race ) {
  1080.     sprintf (errmsg, "Your %s is broken.", bow->name);
  1081.     new_draw_info(NDI_UNIQUE, 0,op, errmsg);
  1082.     op->contr->count_left=0;
  1083.     return;
  1084.   }
  1085.   if ((arrow=find_arrow(op, bow->race)) == NULL) {
  1086.     sprintf (errmsg, "You have no %s left.", bow->race);
  1087.     new_draw_info(NDI_UNIQUE, 0,op,errmsg);
  1088.     op->contr->count_left=0;
  1089.     return;
  1090.   }
  1091.   if(wall(op->map,op->x+freearr_x[dir],op->y+freearr_y[dir])) {
  1092.     new_draw_info(NDI_UNIQUE, 0,op,"Something is in the way.");
  1093.     op->contr->count_left=0;
  1094.     return;
  1095.   }
  1096.   /* this should not happen, but sometimes does */
  1097.   if (arrow->nrof==0) {
  1098.     remove_ob(arrow);
  1099.     free_object(arrow);
  1100.     return;
  1101.   }
  1102.   left = arrow; /* these are arrows left to the player */
  1103.   arrow = get_split_ob(arrow, 1);
  1104.   set_owner(arrow,op);
  1105.   arrow->direction=dir;
  1106.   arrow->x = op->x;
  1107.   arrow->y = op->y;
  1108.   arrow->speed = 1;
  1109.   op->speed_left = 0.01 - (float) FABS(op->speed) * 100 / bow->stats.sp;
  1110.   fix_player(op);
  1111.   update_ob_speed(arrow);
  1112.   arrow->speed_left = 0;
  1113.   arrow->face  = &new_faces[arrow->arch->faces[dir]];
  1114.   arrow->stats.sp = arrow->stats.wc; /* save original wc and dam */
  1115.   arrow->stats.hp = arrow->stats.dam; 
  1116.   arrow->stats.dam += (QUERY_FLAG(bow, FLAG_NO_STRENGTH) ?
  1117.               0 : dam_bonus[op->stats.Str]) +
  1118.             bow->stats.dam + bow->magic + arrow->magic;
  1119.   arrow->stats.wc = 20 - bow->magic - arrow->magic - op->level -
  1120.     dex_bonus[op->stats.Dex] - thaco_bonus[op->stats.Str] - arrow->stats.wc -
  1121.     bow->stats.wc;
  1122.   
  1123.   arrow->map = op->map;
  1124.   SET_FLAG(arrow, FLAG_FLYING);
  1125.   SET_FLAG(arrow, FLAG_FLY_ON);
  1126.   SET_FLAG(arrow, FLAG_WALK_ON);
  1127. #ifdef SOUND_EFFECTS
  1128.   play_sound_map(op->map, op->x, op->y, SOUND_FIRE_ARROW);
  1129. #endif
  1130.   D_LOCK(op);
  1131.   insert_ob_in_map(arrow,op->map);
  1132.   move_arrow(arrow);
  1133.   D_UNLOCK(op);
  1134.   if (op->contr->eric_server > 0) {
  1135.     if (QUERY_FLAG(left, FLAG_FREED))
  1136.       esrv_del_item(op->contr->eric_server, left->count);
  1137.     else
  1138.       esrv_send_item(op, left);
  1139.   }  
  1140. }
  1141.  
  1142. void fire(object *op,int dir) {
  1143.   object *weap=NULL;
  1144.   int spellcost=0;
  1145.  
  1146.   /* op->hide needs to be checked here -b.t.*/ 
  1147.   if (op->contr->tmp_invis && !op->hide) {     /* tmp invis goes away now */
  1148.     op->invisible = 0;
  1149.     op->contr->tmp_invis = 0;
  1150.     update_object(op);
  1151.   }
  1152.    /* a check for players, make sure things are groovy. This routine
  1153.     * will change the skill of the player as appropriate in order to
  1154.     * fire whatever is requested. In the case of spells (range_magic)
  1155.     * it handles whether cleric or mage spell is requested to be cast. 
  1156.     * -b.t. 
  1157.     */ 
  1158. #ifdef ALLOW_SKILLS 
  1159.   if(op->type==PLAYER&&!QUERY_FLAG(op,FLAG_WIZ)) 
  1160.     if(!check_skill_to_fire(op)) return;
  1161. #endif
  1162.  
  1163.   switch(op->contr->shoottype) {
  1164.   case range_none:
  1165.     return;
  1166.  
  1167.   case range_bow:
  1168.     fire_bow(op, dir);
  1169.     return;
  1170.  
  1171.   case range_magic: /* Casting spells */
  1172.  
  1173.     op->contr->shoottype= range_magic;
  1174.  
  1175.     spellcost=cast_spell(op,op,dir,op->contr->chosen_spell,0,spellNormal,NULL);
  1176.  
  1177.     if(spells[op->contr->chosen_spell].cleric)
  1178.         op->stats.grace-=spellcost;
  1179.     else
  1180.     op->stats.sp-=spellcost;
  1181.  
  1182.     draw_stats(op);
  1183.  
  1184.     return;
  1185.  
  1186.   case range_wand:
  1187.     for(weap=op->inv;weap!=NULL;weap=weap->below)
  1188.       if(weap->type==WAND&&QUERY_FLAG(weap, FLAG_APPLIED))
  1189.     break;
  1190.     if(weap==NULL) {
  1191.       new_draw_info(NDI_UNIQUE, 0,op,"You have no wand readied.");
  1192.       op->contr->count_left=0;
  1193.       return;
  1194.     }
  1195.     if(weap->stats.food<=0) {
  1196. #ifdef SOUND_EFFECTS
  1197.       play_sound_player_only(op->contr, SOUND_WAND_POOF);
  1198. #endif
  1199.       new_draw_info(NDI_UNIQUE, 0,op,"The wand says poof.");
  1200.       return;
  1201.     }
  1202.     if(cast_spell(op,weap,dir,op->contr->chosen_item_spell,0,spellWand,NULL)) {
  1203.       SET_FLAG(op, FLAG_BEEN_APPLIED); /* You now know something about it */
  1204.       if (!(--weap->stats.food))
  1205.       {
  1206.     object *tmp;
  1207.     if (weap->arch) {
  1208.       CLEAR_FLAG(weap, FLAG_ANIMATE);
  1209.       weap->face = weap->arch->clone.face;
  1210.       weap->speed = 0;
  1211.       update_ob_speed(weap);
  1212.     }
  1213.     if ((tmp=is_player_inv(weap)))
  1214.       draw_inventory_faces(tmp);
  1215.       }
  1216.     }
  1217.     return;
  1218.   case range_rod:
  1219.   case range_horn:
  1220.     for(weap=op->inv;weap!=NULL;weap=weap->below)
  1221.       if(QUERY_FLAG(weap, FLAG_APPLIED)&&
  1222.      weap->type==(op->contr->shoottype==range_rod?ROD:HORN))
  1223.     break;
  1224.     if(weap==NULL) {
  1225.       char buf[MAX_BUF];
  1226.       sprintf(buf, "You have no %s readied.",
  1227.     op->contr->shoottype == range_rod ? "rod" : "horn");
  1228.       new_draw_info(NDI_UNIQUE, 0,op, buf);
  1229.       op->contr->count_left=0;
  1230.       return;
  1231.     }
  1232.     if(weap->stats.hp<spells[weap->stats.sp].sp) {
  1233.       LOG(llevDebug,"Horn/rod: %d < %d (%d)\n", weap->stats.hp, spells[weap->stats.sp].sp, weap->stats.sp);
  1234. #ifdef SOUND_EFFECTS
  1235.       play_sound_player_only(op->contr, SOUND_WAND_POOF);
  1236. #endif
  1237.       if (op->contr->shoottype == range_rod)
  1238.     new_draw_info(NDI_UNIQUE, 0,op,"The rod whines for a while, but nothing happens.");
  1239.       else
  1240.     new_draw_info(NDI_UNIQUE, 0,op,
  1241.               "No matter how hard you try you can't get another note out.");
  1242.       return;
  1243.     }
  1244.     if(cast_spell(op,weap,dir,op->contr->chosen_item_spell,0,
  1245.        op->contr->shoottype == range_rod ? spellRod : spellHorn,NULL)) {
  1246.       SET_FLAG(op, FLAG_BEEN_APPLIED); /* You now know something about it */
  1247.       drain_rod_charge(weap);
  1248.     }
  1249.     return;
  1250.   case range_scroll: /* Control summoned monsters from scrolls */
  1251.     if(op->contr->golem==NULL) {
  1252.       op->contr->shoottype=range_none;
  1253.       op->contr->chosen_spell= -1;
  1254.       draw_stats(op);
  1255.     }
  1256.     else 
  1257.     control_golem(op->contr->golem, dir);
  1258.     return;
  1259.   case range_skill:
  1260.     if(!op->chosen_skill) { 
  1261.     if(op->type==PLAYER)
  1262.               new_draw_info(NDI_UNIQUE, 0,op,"You have no applicable skill to use.");
  1263.     return;
  1264.     }
  1265.     (void) do_skill(op,dir,NULL);
  1266.     return;
  1267.  
  1268. #if 0
  1269.   case 10: /* Thrown items */
  1270.     new_draw_info(NDI_UNIQUE, 0,op,"Throw is unimplemented as of now.");
  1271.     return;
  1272.     tmp=op->inv;
  1273.     if(tmp==NULL) {
  1274.       new_draw_info(NDI_UNIQUE, 0,op,"You have nothing to throw.");
  1275.       op->contr->count_left=0;
  1276.       return;
  1277.     }
  1278.     if((tmp->weight/1000)>max_carry[op->stats.Str]/2) {
  1279.       sprintf(buf,"You're not strong enough to throw %s.",tmp->name);
  1280.       new_draw_info(NDI_UNIQUE, 0,op,buf);
  1281.       op->contr->count_left=0;
  1282.       return;
  1283.     }
  1284.     if(tmp->type!=BOMB&&(tmp->speed||IS_ALIVE(tmp))) {
  1285.       sprintf(buf,"You can only throw dead objects, not the %s.",tmp->name);
  1286.       new_draw_info(NDI_UNIQUE, 0,op,buf);
  1287.       op->contr->count_left=0;
  1288.       return;
  1289.     }
  1290.     if(tmp->type!=BOMB)
  1291.       update_ob_speed(tmp,0.5);
  1292.     tmp->direction=dir;
  1293.     tmp->thrown=max_carry[op->stats.Str]/(tmp->weight/500);
  1294.     if(tmp->thrown<1) tmp->thrown=1;
  1295.     if(tmp->thrown>10) tmp->thrown=10;
  1296.     tmp->thrownthaco=
  1297.       20-op->level-dex_bonus[op->stats.Dex]-thaco_bonus[op->stats.Str];
  1298.     set_owner(tmp,op);
  1299.     move_thrown(tmp);
  1300.     return;
  1301. #endif
  1302.   default:
  1303.     new_draw_info(NDI_UNIQUE, 0,op,"Illegal shoot type.");
  1304.     op->contr->count_left=0;
  1305.     return;
  1306.   }
  1307. }
  1308.  
  1309. /* This function is just part of a breakup from move_player.
  1310.  * It should keep the code cleaner.
  1311.  * When this is called, the players direction has been updated
  1312.  * (taking into accoutn confusion.)  The player is also actually
  1313.  * going to try and move (not fire weapons).
  1314.  */
  1315.  
  1316. void move_player_attack(object *op, int dir)
  1317. {
  1318.   object *tmp, *tmp2;
  1319.   int nx=freearr_x[dir]+op->x,ny=freearr_y[dir]+op->y;
  1320.  
  1321.  
  1322.   /* If braced, or can't move to the square, and it is not out of the
  1323.    * map, attack it.  Note order of if statement is important - don't
  1324.    * want to be calling move_ob if braced, because move_ob will move the
  1325.    * player.  This is a pretty nasty hack, because if we could
  1326.    * move to some space, it then means that if we are braced, we should
  1327.    * do nothing at all.  As it is, if we are braced, we go through
  1328.    * quite a bit of processing.  However, it probably is less than what
  1329.    * move_ob uses.
  1330.    */
  1331.   if ((op->contr->braced || !move_ob(op,dir)) &&
  1332.     !out_of_map(op->map,nx,ny)) {
  1333.     
  1334.     op->contr->has_hit = 1; /* The last action was to hit, so use weapon_sp */
  1335.  
  1336.     if ((tmp=get_map_ob(op->map,nx,ny))==NULL) {
  1337. /*    LOG(llevError,"player_move_attack: get_map_ob returns NULL, but player can not more there.\n");*/
  1338.     return;
  1339.     }
  1340.  
  1341.     /* Go through all the objects, and stop if we find one of interest. */
  1342.     while (tmp->above!=NULL) {
  1343.       if ((QUERY_FLAG(tmp,FLAG_ALIVE) || QUERY_FLAG(tmp,FLAG_CAN_ROLL)
  1344.         || tmp->type ==LOCKED_DOOR) && tmp!=op)
  1345.         break;
  1346.       tmp=tmp->above;
  1347.     }
  1348.     
  1349.     if (tmp==NULL)    /* This happens anytime the player tries to move */
  1350.     return;        /* into a wall */
  1351.  
  1352.     if(tmp->head != NULL)
  1353.       tmp = tmp->head;
  1354.  
  1355.     /* This blocks deals with opening a normal door.  We look for a key,
  1356.      * and if we found one, break the door.  If not, let normal attack
  1357.      * code deal with it.
  1358.      */
  1359.     if (tmp->type==DOOR && tmp->stats.hp>=0) {
  1360.       tmp2=op->inv;
  1361.       while(tmp2!=NULL&&tmp2->type!=KEY) /* Find a key */
  1362.     tmp2=tmp2->below;
  1363.  
  1364.       if(tmp2!=NULL) {    /* we found a key */
  1365. #ifdef SOUND_EFFECTS
  1366.     play_sound_map(op->map, op->x, op->y, SOUND_OPEN_DOOR);
  1367. #endif
  1368.     decrease_ob(tmp2); /* Use up one of the keys */
  1369.     hit_player(tmp,9999,op,AT_PHYSICAL); /* Break through the door */
  1370.     if(tmp->inv && tmp->inv->type ==RUNE) spring_trap(tmp->inv,op);    
  1371.       }
  1372.     }
  1373.  
  1374.     /* This area deals with locked doors.  These are doors that require
  1375.      * special keys.
  1376.      */
  1377.  
  1378.     if(tmp->type==LOCKED_DOOR) {
  1379.       tmp2=op->inv;
  1380.       while(tmp2 && (tmp2->type != SPECIAL_KEY ||
  1381.         tmp2->slaying != tmp->slaying)) /* Find the key */
  1382.     tmp2=tmp2->below;
  1383.  
  1384.     if(tmp2) {
  1385.       decrease_ob_nr(tmp2, 1); /* Use the key */
  1386.       remove_door2(tmp); /* remove door without violence ;-) */
  1387. #ifdef SOUND_EFFECTS
  1388.       play_sound_map(op->map, op->x, op->y, SOUND_OPEN_DOOR);
  1389. #endif
  1390.       } else if (tmp->msg) /* show door's message if present */
  1391.         new_draw_info(NDI_UNIQUE | NDI_NAVY, 0, op, tmp->msg);
  1392.     }
  1393.  
  1394.     /* The following deals with possibly attacking peaceful
  1395.      * or frienddly creatures.  Basically, all players are considered
  1396.      * unaggressive.  If the moving player has peaceful set, then the
  1397.      * object should be pushed instead of attacked.  It is assumed that
  1398.      * if you are braced, you will not attack friends accidently,
  1399.      * and thus will not push them.
  1400.      */
  1401.  
  1402.     if (tmp->enemy != op &&
  1403.       (tmp->type==PLAYER || QUERY_FLAG(tmp,FLAG_UNAGGRESSIVE)
  1404.     || QUERY_FLAG(tmp, FLAG_FRIENDLY)) &&
  1405.     op->contr->peaceful && (!op->contr->braced)) {
  1406. #ifdef SOUND_EFFECTS
  1407.       play_sound_map(op->map, op->x, op->y, SOUND_PUSH_PLAYER);
  1408. #endif
  1409.       (void) push_ob(tmp,dir,op);
  1410.     }
  1411.  
  1412.       /* If the object is a boulder or other rollable object, then
  1413.        * roll it if not braced.  You can't roll it if you are braced.
  1414.        */
  1415.       else if(QUERY_FLAG(tmp,FLAG_CAN_ROLL)&&(!op->contr->braced))
  1416.       recursive_roll(tmp,dir,op);
  1417.  
  1418.       /* Any generic living creature.  Including things like doors.
  1419.        * Way it works is like this:  First, it must have some hit points
  1420.        * and be living.  Then, it must be one of the following:
  1421.        * 1) Not a player, 2) A player, but of a different party.  Note
  1422.        * that party_number -1 is no party, so attacks can still happen.
  1423.        */
  1424.  
  1425.       else 
  1426. #ifdef SIMPLE_PARTY_SYSTEM    
  1427.     if ((tmp->stats.hp>=0) && QUERY_FLAG(tmp, FLAG_ALIVE) &&
  1428.     ((tmp->type!=PLAYER || op->contr->party_number==-1 ||
  1429.     op->contr->party_number!=tmp->contr->party_number))) {
  1430. #else
  1431.     if ((tmp->stats.hp>=0) && QUERY_FLAG(tmp, FLAG_ALIVE)) {
  1432. #endif
  1433.  
  1434. #ifdef ALLOW_SKILLS
  1435.             skill_attack(tmp, op, 0, NULL); 
  1436. #else 
  1437.             (void) attack_ob(tmp, op);
  1438. #endif 
  1439.       /* If attacking another player, that player gets automatic
  1440.        * hitback, and doesn't loose luck either.
  1441.        */
  1442.       if (tmp->type == PLAYER && tmp->stats.hp >= 0 &&
  1443.          !tmp->contr->has_hit)
  1444.       {
  1445.         short luck = tmp->stats.luck;
  1446.         tmp->contr->has_hit = 1;
  1447. #ifdef ALLOW_SKILLS
  1448.         skill_attack(op, tmp, 0, NULL); 
  1449. #else
  1450.         (void) attack_ob(op, tmp);
  1451. #endif
  1452.         tmp->stats.luck = luck;
  1453.       }
  1454.       if(op->contr->tmp_invis) {
  1455.         op->contr->tmp_invis=0;
  1456.         op->invisible=0;
  1457.         op->hide=0;
  1458.         update_object(op);
  1459.       }
  1460.     }
  1461.     }
  1462. }
  1463.  
  1464. int move_player(object *op,int dir) {
  1465.   int num1;
  1466.   int face = dir ? (dir - 1) / 2 : -1;
  1467.  
  1468.   if(op->map == NULL || op->map->in_memory != MAP_IN_MEMORY)
  1469.     return 0;
  1470.  
  1471.   /* peterm:  added following line */
  1472.   op->facing = dir;
  1473.   if(QUERY_FLAG(op,FLAG_CONFUSED) && dir)
  1474.     dir = absdir(dir + RANDOM()%3 + RANDOM()%3 - 2);
  1475.  
  1476. /* For Hidden players- a chance of becoming 'unhidden'
  1477.  * every time they move - as we subtract off 'invisibility'
  1478.  * from the player bt. (thomas@astro.psu.edu) 
  1479.  */ 
  1480.   if(op->hide>0) {  
  1481.     num1=RANDOM()%10 + op->map->difficulty;
  1482.     if(num1>op->invisible) {
  1483.         char buf[MAX_BUF];
  1484.     op->contr->tmp_invis=0;
  1485.         op->hide=0;
  1486.         op->invisible=0;
  1487.     sprintf(buf,"You moved too much! You are visible!"); 
  1488.         new_draw_info(NDI_UNIQUE, 0,op,buf);
  1489.     } else
  1490.         op->invisible-=num1;
  1491.   }
  1492.  
  1493.   if(op->contr->fire_on)
  1494.     fire(op,dir);
  1495.   else move_player_attack(op,dir);
  1496.  
  1497.   if((check_pick(op)&&op->contr->run_on)||
  1498.      (op->contr->berzerk&&op->contr->run_on))
  1499.     op->direction=dir;
  1500.   else
  1501.     op->direction=0;
  1502.   if(face != -1)
  1503.     op->face = &new_faces[op->arch->faces[face]];
  1504.   update_object(op);
  1505.   return 0;
  1506. }
  1507.  
  1508. int has_cleared_window(Window w,Window *win_clr,int max) {
  1509.   for(max--;max>=0;max--)
  1510.     if(win_clr[max]==w)
  1511.       return 1;
  1512.   return 0;
  1513. }
  1514.  
  1515.  
  1516. /* splitting this out created a 292 line function !!!!!!*/
  1517. /* Returns whether or not to keep processing events */
  1518. int handle_buttonpress(object *op)
  1519. {
  1520.   /* Need some more local variables */
  1521.   int i=0,y=op->contr->gevent.xbutton.y,x=op->contr->gevent.xbutton.x,
  1522.   button=op->contr->gevent.xbutton.button;
  1523.   int dx=(x-2)/24-5,dy=(y-2)/24-5;
  1524.   object *inv;
  1525.  
  1526.   inv = op->inv;
  1527.   if(op->contr->state||QUERY_FLAG(op,FLAG_REMOVED))
  1528.     return 1;
  1529.   if(op->above) {
  1530.     remove_ob(op);
  1531.     insert_ob_in_map(op,op->map);
  1532.   }
  1533.   if(op->contr->gevent.xbutton.window==op->contr->win_game) {
  1534.     switch (button) {
  1535.      case 1:
  1536.       {
  1537.     if(dx<WINLEFT||dx>WINRIGHT||dy<WINUPPER||dy>WINLOWER)
  1538.       return 1;
  1539.     if(op->contr->blocked_los[dx+5][dy+5])
  1540.       return 1;
  1541.     look_at(op,dx,dy);
  1542.     op->contr->last_cmd=(dx||dy)?0:2;
  1543.       }
  1544.       return 1;
  1545.  
  1546.      case 2:
  1547.      case 3:
  1548.       if (button == 2)
  1549.     op->contr->fire_on=1;
  1550.       if (x<115)
  1551.     i = 0;
  1552.       else if (x>149)
  1553.     i = 6;
  1554.       else i =3;
  1555.  
  1556.       if (y>152)
  1557.     i += 2;
  1558.       else if (y>115)
  1559.     i++;
  1560.  
  1561.       switch (i) {
  1562.        case 0: move_player (op,8);break;
  1563.        case 1: move_player (op,7);break;
  1564.        case 2: move_player (op,6);break;
  1565.        case 3: move_player (op,1);break;
  1566.        case 5: move_player (op,5);break;
  1567.        case 6: move_player (op,2);break;
  1568.        case 7: move_player (op,3);break;
  1569.        case 8: move_player (op,4);break;
  1570.       }
  1571.       if (button == 2)
  1572.     op->contr->fire_on=0;
  1573.       if (i>=0 && i<=8) return 1;
  1574.       return 0;
  1575.     }
  1576.     return 1;
  1577.   } else if(op->contr->gevent.xbutton.window == op->contr->win_message) {
  1578. #ifdef USE_BUTTONS
  1579.     if (y>62) {
  1580.       extern int opX [NUMOPBUTTS];
  1581.       for (i=0; i< NUMOPBUTTS+1; i++) {
  1582.       if (x>opX[i]&&x<opX[i]+64&&y>opY[i]&&y<opY[i]+18) {
  1583.     if  (i == CHANGE_button) {
  1584.       if (button == 1)
  1585.         change_spell (op,'+');
  1586.       else if (button == 2)
  1587.         change_spell (op,'-');
  1588.     } else if (i == APPLY_button) {
  1589.       if (button == 1)
  1590.         apply_below (op);
  1591.       else if (button ==2) {
  1592.         apply_inventory(op);
  1593.         if (op->contr->show_what == show_applied ||
  1594.             op->contr->show_what == show_unapplied)
  1595.           draw_inventory(op);
  1596.       }
  1597.     } else if (i == TALK_button)
  1598.       ;
  1599.     else if (i == PEACE_button) {
  1600.       char *pbuf="peaceful"; /*parse_string needs a writable string */
  1601.       parse_string (op,pbuf);
  1602.     }
  1603.       }
  1604.       }
  1605.     } else {
  1606.       for (i=0;i<NUMDIRBUTTS+1;i++)
  1607.       if(x>dirX[i]&&x<dirX[i]+dirW&&y>dirY[i]&&y<dirY[i]+18) {
  1608.     if (button == 2)
  1609.       op->contr->fire_on=1;
  1610.     else if (button == 3)
  1611.       op->contr->run_on=1;
  1612.     switch (i) {
  1613.      case NW_button: move_player (op,8);return 1;
  1614.      case NO_button: move_player (op,1);return 1;
  1615.      case NE_button: move_player (op,2);return 1;
  1616.      case WE_button: move_player (op,7);return 1;
  1617.      case BR_button: return 1;
  1618.      case EA_button: move_player (op,3);return 1;
  1619.      case SW_button: move_player (op,6);return 1;
  1620.      case SO_button: move_player (op,5);return 1;
  1621.      case SE_button: move_player (op,4);return 1;
  1622.      default:return 1;
  1623.     }
  1624.     op->contr->fire_on=0;
  1625.     op->contr->run_on=0;
  1626.       }
  1627.     }
  1628. #else
  1629.     return 1;
  1630. #endif
  1631.   } else if(op->contr->gevent.xbutton.window==op->contr->win_inv) {
  1632.     int dy=(y-16)/24+op->contr->scroll_inv;
  1633.     object *tmp;
  1634.  
  1635.     if(x>270) {
  1636.       dy-=op->contr->scroll_inv;
  1637.       switch(button) {
  1638.        case 1:
  1639.       op->contr->scroll_inv-=dy>0?dy:1;
  1640.       draw_inventory(op);
  1641.       return 1;
  1642.        case 2:
  1643.       {
  1644.     int objects,scroll;
  1645.     object *tmp;
  1646.  
  1647.     for(tmp=inv,objects=0;tmp!=NULL;tmp=tmp->below)
  1648.       if (show_what_object(tmp, op->contr->show_what)) 
  1649.         objects++;
  1650.     scroll=(y-17)*objects/op->contr->barlength_inv;
  1651.     if(op->contr->scroll_inv==scroll)
  1652.       return 1;
  1653.     op->contr->scroll_inv=scroll;
  1654.     draw_inventory(op);
  1655.     return 1;
  1656.       }
  1657.        case 3:
  1658.       op->contr->scroll_inv+=dy>0?dy:1;
  1659.       draw_inventory(op);
  1660.       return 1;
  1661.       }
  1662.       return 1;
  1663.     }
  1664.     if(dy<0)
  1665.       return 1;
  1666.     for(tmp=inv,i=0;tmp!=NULL;tmp=tmp->below) {
  1667.       while(tmp != NULL && (!show_what_object(tmp, op->contr->show_what)))
  1668.       tmp = tmp->below;
  1669.       if (tmp == NULL)
  1670.       return 1;
  1671.       if (i++ == dy) {
  1672.       switch(button) {
  1673.        case 1:
  1674.     if(op->contr->gevent.xbutton.state == ShiftMask) {
  1675.       if(QUERY_FLAG(tmp,FLAG_INV_LOCKED))
  1676.         unlock_inv(op,tmp);
  1677.       else
  1678.         lock_inv(op,tmp);
  1679.     }
  1680.     else
  1681.       examine(op,tmp);
  1682.     return 1;
  1683.        case 2:
  1684.     apply(op,tmp);
  1685.     if (op->contr->show_what == show_applied || op->contr->show_what==show_unapplied)
  1686.       draw_inventory(op);
  1687.     return 1;
  1688.        case 3:
  1689.     if(tmp->type==CONTAINER && QUERY_FLAG(tmp,FLAG_APPLIED)) {
  1690.       if(op->container==tmp) return 1; /* fix an endless loop problem */
  1691.       for(inv=tmp->inv;inv!=NULL;) {
  1692.         /* The drop may fail if dropping from container TO container */
  1693.         tmp=inv->below;
  1694.         drop(op,inv);
  1695.         inv=tmp;
  1696.       }
  1697.     }
  1698.     else drop(op,tmp);
  1699.     return 1;
  1700.       }
  1701.       return 1;
  1702.       }
  1703.     }
  1704.     return 1;
  1705.   } else if(op->contr->gevent.xbutton.window==op->contr->win_look) {
  1706.     int dy=(y-16)/24+op->contr->scroll_look;
  1707.     object *top, *tmp;
  1708.  
  1709.     if(x>270) {
  1710.       dy-=op->contr->scroll_look;
  1711.       switch(button) {
  1712.        case 1:
  1713.       op->contr->scroll_look-=dy>0?dy:1;
  1714.       draw_look(op);
  1715.       return 1;
  1716.        case 2:
  1717.       {
  1718.     int objects,scroll;
  1719.  
  1720.     /* Eneq(@csd.uu.se): ... */    
  1721.  
  1722.     for(tmp=(op->container?op->container->inv:op->below),objects=0;tmp!=NULL;tmp=tmp->below)
  1723.       if(!(tmp->invisible))
  1724.         objects++;
  1725.     scroll=(y-17)*objects/op->contr->barlength_look;
  1726.     if(op->contr->scroll_look==scroll)
  1727.       return 1;
  1728.     op->contr->scroll_look=scroll;
  1729.     draw_look(op);
  1730.     return 1;
  1731.       }
  1732.        case 3:
  1733.       op->contr->scroll_look+=dy>0?dy:1;
  1734.       draw_look(op);
  1735.       return 1;
  1736.       }
  1737.       return 1;
  1738.     }
  1739.     if(dy<0)
  1740.       return 1;
  1741.     if(wall(op->map,op->x,op->y))
  1742.       return 1;
  1743.       
  1744.     /* Eneq(@csd.uu.se): Altered container-treatment, displays
  1745.        contents in look-window. */
  1746.     if (op->container)
  1747.       top=op->container->inv;
  1748.     else
  1749.       for(top=get_map_ob(op->map,op->x,op->y);
  1750.     top!=NULL&&top->above!=NULL&&top->above!=op;top=top->above);
  1751.  
  1752.     /* Moved i<dy out of for loop.  This is because with it in
  1753.      * the for loop, a check to see if it is a valid item for the
  1754.      * look window is never made.  master@rahul.net
  1755.      */
  1756.     for(tmp=top,i=0;(tmp!=NULL)&&!(tmp->above&&
  1757.                              QUERY_FLAG(tmp->above,FLAG_IS_FLOOR))
  1758.       ;tmp=tmp->below)
  1759.       if (LOOK_OBJ(tmp)) {
  1760.       i++;
  1761.       if (i>dy) break;
  1762.       }
  1763.     if(i<=dy)                 /* means we did not find enough valid objects */
  1764.     return 1;
  1765.     switch(button) {
  1766.      case 1:
  1767.       examine(op,tmp);
  1768.       return 1;
  1769.      case 2:
  1770.       apply(op,tmp);
  1771.       draw_look(op);
  1772.       return 1;
  1773.      case 3:
  1774.       pick_up(op,tmp);
  1775.       return 1;
  1776.     }
  1777.     return 1;
  1778.   } else if(op->contr->gevent.xbutton.window==op->contr->win_info) {
  1779.     object *tmp;
  1780.     switch(button) {
  1781.      case 1:
  1782.      case 2:
  1783.       if(op->contr->last_cmd!=1) {
  1784.       inventory(op,NULL);
  1785.       op->contr->last_cmd=1;
  1786.       return 1;
  1787.       }
  1788.       for(tmp=inv,i=0;tmp!=NULL&&i<(y-13)/13;tmp=tmp->below,i++);
  1789.       if(tmp!=NULL) {
  1790.       if(button==1)
  1791.     apply(op,tmp);
  1792.       else
  1793.     drop(op,tmp);
  1794.       inventory(op,NULL);
  1795.       op->contr->last_cmd=1;
  1796.       }
  1797.       return 1;
  1798.      case 3:
  1799.       if(op->contr->last_cmd!=2) {
  1800.       look_at(op,0,0);
  1801.       op->contr->last_cmd=2;
  1802.       return 1;
  1803.       }
  1804.       if(wall(op->map,op->x,op->y))
  1805.       return 1;
  1806.       for(tmp=op->below,i=0;tmp!=NULL&&
  1807.     (QUERY_FLAG(op,FLAG_WIZ)||(tmp->type!=EARTHWALL&&tmp!=op))&&i<(y-13)/13;
  1808.     tmp=tmp->below,i++);
  1809.       if(tmp!=NULL) {
  1810.       pick_up(op,tmp);
  1811.       op->contr->last_cmd=0;
  1812.       }
  1813.       return 1;
  1814.      default:
  1815.       new_draw_info(NDI_UNIQUE, 0,op,"Undefined button.");
  1816.       return 1;
  1817.     }
  1818.   }
  1819.   abort(); /* eanders: claim is this should never be reached; 
  1820.         if it is, look at 91.5 code to determine what the value of
  1821.         repeat was supposed to be and make sure you don't reach here. */
  1822. }
  1823.  
  1824. int receive_play_again(object *op, char key)
  1825. {
  1826.     if(key=='q'||key=='Q') {
  1827.       remove_friendly_object(op);
  1828.       leave(op->contr);
  1829.       return 2;
  1830.     }
  1831.     else if(key=='a'||key=='A') {
  1832.       object *tmp;
  1833.       remove_friendly_object(op);
  1834.       op->contr->ob=get_player(op->contr,op->map);
  1835.       tmp=op->contr->ob;
  1836.       add_friendly_object(tmp);
  1837.       tmp->contr->password[0]='~';
  1838.       if(tmp->name!=NULL)
  1839.           free_string(tmp->name);
  1840.       get_name(tmp);
  1841.       add_refcount(tmp->name = op->name);
  1842.       op->type=DEAD_OBJECT;
  1843.       free_object(op);
  1844.       op=tmp;
  1845.     }
  1846.     return 0;
  1847. }
  1848.  
  1849. /* splitting this out produced a 250 line function !!!!! */
  1850. /* return 1 = repeat, return 0 = don't repeat, return 2 = immediate return */
  1851. /* needs keycode, gkey, char (text[0]) */
  1852. int handle_keypress(object *op,unsigned int keycode,KeySym keysym,char key)
  1853. {
  1854.   op->contr->count_left=0;
  1855.   switch(op->contr->state) {
  1856.    case ST_PLAYING:
  1857.     return parse_key(op,key,keycode,
  1858.                keysym);
  1859.  
  1860.    case ST_PLAY_AGAIN:
  1861.     return receive_play_again(op, key);
  1862.  
  1863.    case ST_ROLL_STAT:
  1864.     return key_roll_stat(op, key);
  1865.  
  1866.    case ST_CHANGE_CLASS:
  1867.     return key_change_class(op, key);
  1868.  
  1869.    case ST_CONFIRM_QUIT:
  1870.     return key_confirm_quit(op, key);
  1871.  
  1872.    case ST_CONFIGURE:
  1873.     configure_keys(op, keycode, keysym);
  1874.     return 1;
  1875.  
  1876.    case ST_GET_NAME:          /* Waiting for player name */
  1877.     receive_player_name(op,key);
  1878.     return 1;
  1879.  
  1880.    case ST_GET_PASSWORD:      /* Waiting for player password */
  1881.    case ST_CONFIRM_PASSWORD:  /* Confirm new password */
  1882.     receive_player_password(op,key);
  1883.     return 1;
  1884.  
  1885.  
  1886.    case ST_MENU_MORE:         /* more items to be listed */
  1887.     shop_listing_more(op);
  1888.     return 0;
  1889.  
  1890.  
  1891. #ifdef SIMPLE_PARTY_SYSTEM
  1892.    case ST_GET_PARTY_PASSWORD:        /* Get password for party */
  1893.     receive_party_password(op,key);
  1894.     return 1;
  1895. #endif /* SIMPLE_PARTY_SYSTEM */
  1896.  
  1897.  
  1898.    default:
  1899.     LOG(llevError,"Illegal state: %d\n",op->contr->state);
  1900.     return 0;
  1901.   }
  1902.   abort(); /* eanders: claim is this should never be reached;
  1903.         if it is, look at 91.5 code to determine what the value of repeat
  1904.         was supposed to be and return the right thing. */
  1905. }
  1906.  
  1907. /* This is similar to handle_player, below, but is only used by the
  1908.  * new client/server stuff.
  1909.  * This is sort of special, in that the new client/server actually uses
  1910.  * the new speed values for commands.
  1911.  *
  1912.  * Returns true if there are more actions we can do.
  1913.  */
  1914. int handle_newcs_player(object *op)
  1915. {
  1916.     if(op->contr->state == ST_PLAYING && op->contr->loading != NULL) {
  1917.     if(op->contr->loading->in_memory == MAP_IN_MEMORY) {
  1918.         LOG(llevDebug,"In handle player, entering map\n");
  1919.         enter_map(op);
  1920.     }
  1921.     else
  1922.         return 0;
  1923.     }
  1924.     if(op->invisible&&!(QUERY_FLAG(op,FLAG_MAKE_INVIS))) {
  1925.     op->invisible--;
  1926.     if(!op->invisible) {
  1927.         CLEAR_FLAG(op, FLAG_UNDEAD);
  1928.         update_object(op);
  1929.     }
  1930.     }
  1931.     draw_stats(op);
  1932.     if(op->direction) {
  1933.     /* All move commands take 1 tick, at least for now */
  1934.     op->speed_left--;
  1935.     if(op->contr->berzerk&&(op->contr->braced||(!op->contr->fire_on)))
  1936.         move_player(op,op->direction);
  1937.     else if(!move_ob(op,op->direction)||!check_pick(op))
  1938.         op->direction=0;
  1939.     if (op->speed_left>0) return 1;
  1940.     else return 0;
  1941.     }
  1942.     return 0;
  1943. }
  1944.  
  1945. void handle_player(object *op) {
  1946.   int repeat,windex=0;
  1947.   char text[10];
  1948.   Window win_clr[10];
  1949.  
  1950.   if(op->contr->state == ST_PLAYING && op->contr->loading != NULL) {
  1951.     op->speed_left++;
  1952.     if(op->contr->loading->in_memory == MAP_IN_MEMORY) {
  1953.       LOG(llevDebug,"In handle player, entering map\n");
  1954.       enter_map(op);
  1955.     }
  1956.     else
  1957.       return;
  1958.   }
  1959.   if(op->invisible&&!(QUERY_FLAG(op,FLAG_MAKE_INVIS))) {
  1960.     op->invisible--;
  1961.     if(!op->invisible) {
  1962.       CLEAR_FLAG(op, FLAG_UNDEAD);
  1963.       update_object(op);
  1964.     }
  1965.   }
  1966.   op->contr->has_hit=0;
  1967.   draw_stats(op);
  1968.   if (op->contr->eric_server>0) {
  1969.     LOG(llevError,"new client/server player called handle_player\n");
  1970.     return;
  1971.   }
  1972.  
  1973.   repeat=1;
  1974.   while(repeat) {
  1975.     if (QUERY_FLAG(op,FLAG_SCARED)) {
  1976.       flee_player(op);
  1977.       return;
  1978.     }
  1979.     repeat=0;
  1980.     if (XEventsQueued(op->contr->gdisp, QueuedAfterReading)==0) {
  1981.  
  1982.       if(op->contr->count_left>0) {
  1983.     int tmp_fire_on=op->contr->fire_on;
  1984.     op->contr->fire_on=op->contr->prev_fire_on;
  1985.     op->contr->count_left--;
  1986.     parse_key(op, op->contr->prev_cmd,
  1987.           op->contr->prev_keycode, op->contr->prev_keysym);
  1988.     op->contr->fire_on=tmp_fire_on;
  1989.       } else if(op->direction)
  1990.     if(op->contr->berzerk&&(op->contr->braced||(!op->contr->fire_on)))
  1991.       move_player(op,op->direction);
  1992.     else if(!move_ob(op,op->direction)||!check_pick(op))
  1993.       op->direction=0;
  1994.       return;
  1995.     }
  1996.     op->contr->idle=0;
  1997.     XNextEvent(op->contr->gdisp,&op->contr->gevent);
  1998.     switch(op->contr->gevent.type) {
  1999.     case ConfigureNotify:
  2000.       if(op->contr->gevent.xconfigure.window==op->contr->win_info)
  2001.     resize_win_info(op->contr,&op->contr->gevent);
  2002.       else if(op->contr->gevent.xconfigure.window==op->contr->win_inv)
  2003.     resize_win_inv(op->contr,&op->contr->gevent);
  2004.       else if(op->contr->gevent.xconfigure.window==op->contr->win_look)
  2005.     resize_win_look(op->contr,&op->contr->gevent);
  2006.       break;
  2007.     case Expose:
  2008.       repeat=1;
  2009.       if(has_cleared_window(op->contr->gevent.xexpose.window,win_clr,windex))
  2010.     break;
  2011.       win_clr[windex++]=op->contr->gevent.xexpose.window;
  2012.       if(op->contr->gevent.xexpose.window==op->contr->win_stats) {
  2013.     XClearWindow(op->contr->gdisp,op->contr->win_stats);
  2014.     op->contr->last_value= -1;
  2015.     draw_stats(op);
  2016.       } else if(op->contr->gevent.xexpose.window==op->contr->win_info)
  2017.     draw_all_info(op);
  2018.       else if(op->contr->gevent.xexpose.window==op->contr->win_inv)
  2019.     draw_all_inventory(op);
  2020.       else if(op->contr->gevent.xexpose.window==op->contr->win_look)
  2021.     draw_all_look(op);
  2022.       else if(op->contr->gevent.xexpose.window==op->contr->win_message)
  2023.     draw_all_message(op);
  2024.       else if(op->contr->gevent.xexpose.window==op->contr->win_game)
  2025.     refresh(op);
  2026.       else if(!op->contr->split_window&&
  2027.           op->contr->gevent.xexpose.window==op->contr->win_root) {
  2028.     XClearWindow(op->contr->gdisp,op->contr->win_root);
  2029.       }
  2030.       op->speed_left++;
  2031.       break;
  2032.     case MappingNotify:
  2033.       op->speed_left++;
  2034.       XRefreshKeyboardMapping(&op->contr->gevent.xmapping);
  2035.       repeat=1;
  2036.       break;
  2037.     case ClientMessage:
  2038.       cmev = (XClientMessageEvent *) & op->contr->gevent;
  2039.       if (cmev->message_type == Protocol_atom && cmev->data.l[0] == Kill_atom) {
  2040.     LOG(llevDebug,"Got WM_DELETE_WINDOW from %s.\n",op->name);
  2041.     if (op->map->in_memory == MAP_IN_MEMORY)
  2042.     {
  2043.       if (!QUERY_FLAG(op,FLAG_REMOVED)) {
  2044.         op->map->players--;
  2045.         remove_ob(op);
  2046.       }
  2047.     }
  2048.     op->contr->state = 1;
  2049.     op->direction = 0;
  2050.     op->contr->count_left = 0;
  2051.     new_draw_info_format(NDI_UNIQUE|NDI_ALL, 0, NULL,
  2052.         "%s lost connection.", op->name);
  2053.  
  2054.     strcpy(op->contr->killer, "lost connection");
  2055.     check_score(op);
  2056.     (void) save_player(op, 0);
  2057.     remove_lock(op->contr);
  2058.  
  2059.     free_player(op->contr);
  2060.     if(first_player==NULL) {
  2061.        if (server_mode != SERVER_ENABLED)
  2062.          exit(0);
  2063.        XCloseDisplay(op->contr->gdisp);
  2064.        LOG(llevDebug, "In server mode: continuing action.\n");
  2065.      }
  2066. #if 0 /* This should crash if it doesn't return! -Frank */
  2067.     if (first_player==NULL)
  2068. #endif /* (Also, free_player() must be before the NULL test!) */
  2069.     return;
  2070.       }
  2071.       break;
  2072.     case ButtonPress:
  2073.     repeat = handle_buttonpress(op);
  2074.     break;
  2075.  
  2076.     case KeyRelease:
  2077.       repeat=1;
  2078.       XLookupString(&op->contr->gevent.xkey,text,10,&op->contr->gkey,NULL);
  2079.       parse_key_release(op);
  2080.       break;
  2081.     case KeyPress:
  2082.       if(!XLookupString(&op->contr->gevent.xkey,text,10,
  2083.      &op->contr->gkey,NULL)) {
  2084.     text[0]='\0';
  2085.       }
  2086.       repeat = handle_keypress(op,op->contr->gevent.xkey.keycode,
  2087.                          op->contr->gkey,text[0]);
  2088.       if (repeat==2)
  2089.     return;
  2090.       break;
  2091.  
  2092.     default:
  2093.       repeat=1;
  2094.     }
  2095.   }
  2096.   if (!op->contr->keyboard_flush) return;
  2097. /* This should work better at removing keystrokes from the Queue
  2098.  * than the old method.  The old method could only remove keystrokes if
  2099.  * they where the first events.  But, if the queue was keyboard, 
  2100.  * keyboard, window, keyboard, it would stop at the window event,
  2101.  * and one keyboard event would still be around.  The following should
  2102.  * remove all wanted events, and nothing more.
  2103.  */
  2104.  
  2105.   while(XCheckMaskEvent(op->contr->gdisp, KeyPressMask | KeyReleaseMask | ButtonPressMask, &op->contr->gevent)) {
  2106.     switch(op->contr->gevent.type) {
  2107.     case KeyPress:
  2108.       XLookupString(&op->contr->gevent.xkey,text,10,&op->contr->gkey,NULL);
  2109.     /* Some keypresses we can't just throw away...: */
  2110.       if((op->contr->gevent.xkey.keycode==op->contr->firekey[0] &&
  2111.       op->contr->gkey==op->contr->firekeysym[0]) ||
  2112.      (op->contr->gevent.xkey.keycode==op->contr->firekey[1] &&
  2113.       op->contr->gkey==op->contr->firekeysym[1]))
  2114.     op->contr->fire_on=1;
  2115.       if((op->contr->gevent.xkey.keycode==op->contr->runkey[0] &&
  2116.       op->contr->gkey==op->contr->runkeysym[0]) ||
  2117.      (op->contr->gevent.xkey.keycode==op->contr->runkey[1] &&
  2118.       op->contr->gkey==op->contr->runkeysym[1]))
  2119.     op->contr->run_on=1;
  2120. /*    LOG(llevDebug,"Through away key %s from input",text);*/
  2121.       continue;
  2122.     case KeyRelease:
  2123.       XLookupString(&op->contr->gevent.xkey,text,10,&op->contr->gkey,NULL);
  2124.       parse_key_release(op);
  2125.       continue;
  2126.     case ButtonPress:
  2127.       continue;
  2128.     default:
  2129.     LOG(llevError,"While flushing keyboard, got unkown X event (%d)\n", op->contr->gevent.type);
  2130.     break;
  2131.     }
  2132.     break;
  2133.   }
  2134. }
  2135.  
  2136.  
  2137. object *esrv_getopfromcid(long client_id)
  2138. {
  2139.   struct pl *l;
  2140.   for(l = first_player;l!= NULL;l=l->next) {
  2141.     if (l->eric_server == client_id)
  2142.       break;
  2143.   }
  2144.   if (l==NULL) {
  2145.     LOG(llevError,"Tried to get CID(%d) which doesn't exist.\n",client_id);
  2146.     abort();
  2147.   }
  2148.   return l->ob;
  2149. }
  2150.  
  2151. object *esrv_get_ob_from_count(object *pl, long count)
  2152. {
  2153.     object *op, *tmp;
  2154.  
  2155.     if (pl->count == count)
  2156.     return pl;
  2157.  
  2158.     for(op = pl->inv; op; op = op->below)
  2159.     if (op->count == count)
  2160.         return op;
  2161.     else if (op->type == CONTAINER && pl->container == op)
  2162.         for(tmp = op->inv; tmp; tmp = tmp->below)
  2163.         if (tmp->count == count)
  2164.             return tmp;
  2165.  
  2166.     for(op = get_map_ob (pl->map, pl->x, pl->y); op; op = op->above)
  2167.     if (op->count == count)
  2168.         return op;
  2169.     else if (op->type == CONTAINER && pl->container == op)
  2170.         for(tmp = op->inv; tmp; tmp = tmp->below)
  2171.         if (tmp->count == count)
  2172.             return tmp;
  2173.     return NULL;
  2174. }
  2175.  
  2176. void esrv_examine_object (object *pl, long tag)
  2177. {
  2178.     object *op = esrv_get_ob_from_count(pl, tag);
  2179.  
  2180.     if (!op) {
  2181.       LOG(llevDebug, "Player '%s' tried examine the unknown object (%d)\n",
  2182.       pl->name, tag);
  2183.       return;
  2184.     }
  2185.     examine (pl, op);
  2186. }
  2187.  
  2188. void esrv_apply_object (object *pl, long tag)
  2189. {
  2190.     object *op = esrv_get_ob_from_count(pl, tag);
  2191.  
  2192.     if (!op) {
  2193.       LOG(llevDebug, "Player '%s' tried apply the unknown object (%d)\n",
  2194.       pl->name, tag);
  2195.       return;
  2196.     }
  2197.     apply (pl, op);
  2198. }
  2199.  
  2200. void esrv_move_object (object *pl, long to, long tag, long nrof)
  2201. {
  2202.     object *op, *env;
  2203.  
  2204.     printf ("esrv_move_object:\n");
  2205.     printf ("Trying to locate object %ld from player %s.\n", tag, pl->name);
  2206.     op = esrv_get_ob_from_count(pl, tag);
  2207.     if (!op) {
  2208.       LOG(llevDebug, "Player '%s' tried to move the unknown object (%ld)\n",
  2209.       pl->name, tag);
  2210.       return;
  2211.     }
  2212.     printf ("and the object was '%s'.\n", op->name);
  2213.  
  2214.     if (!to) {    /* drop it to the ground */
  2215.     printf ("Drop it on the ground.\n");
  2216.       drop_object (pl, op, nrof);
  2217.       return;
  2218.     } else if (to == pl->count) {     /* pick it up to the inventory */
  2219.       /* later */
  2220.       printf ("Pickup not impl. yet.\n");
  2221.       pick_up_object (pl, pl, op, nrof);
  2222.       return ;
  2223.     }
  2224.     printf ("It was not dropped or picked up, put it in sack (%ld).\n", to);
  2225.     env = esrv_get_ob_from_count(pl, to);
  2226.     if (!env) {
  2227.       LOG(llevDebug, 
  2228.       "Player '%s' tried to move object to the unknown location (%d)\n",
  2229.       pl->name, to);
  2230.       return;
  2231.     }
  2232.     printf ("Sacks name was '%s'.\n", env->name);
  2233.     put_object_in_sack (pl, env, op, nrof);
  2234. }
  2235.  
  2236.  
  2237. void esrv_quit_player(long client_id)
  2238. {
  2239.   struct pl *l;
  2240.   for(l = first_player;l!= NULL;l=l->next) {
  2241.     if (l->eric_server == client_id)
  2242.       break;
  2243.   }
  2244.   if (l!=NULL) {
  2245.     if(!QUERY_FLAG(l->ob,FLAG_REMOVED)) {
  2246.       terminate_all_pets(l->ob);
  2247.       remove_ob(l->ob);
  2248.     }
  2249.     leave(l);
  2250.   }
  2251. }
  2252.  
  2253.  
  2254. int save_life(object *op) {
  2255.   object *tmp;
  2256.   char buf[MAX_BUF];
  2257.   if(!QUERY_FLAG(op,FLAG_LIFESAVE))
  2258.     return 0;
  2259.   for(tmp=op->inv;tmp!=NULL;tmp=tmp->below)
  2260.     if(QUERY_FLAG(tmp, FLAG_APPLIED)&&QUERY_FLAG(tmp,FLAG_LIFESAVE)) {
  2261. #ifdef SOUND_EFFECTS
  2262.       play_sound_map(op->map, op->x, op->y, SOUND_OB_EVAPORATE);
  2263. #endif
  2264.       sprintf(buf,"Your %s vibrates violently, then evaporates.",
  2265.           query_name(tmp));
  2266.       new_draw_info(NDI_UNIQUE, 0,op,buf);
  2267.       remove_ob(tmp);
  2268.       free_object(tmp);
  2269.       CLEAR_FLAG(op, FLAG_LIFESAVE);
  2270.       if(op->stats.hp<0)
  2271.     op->stats.hp = op->stats.maxhp;
  2272.       if(op->stats.food<0)
  2273.     op->stats.food = 999;
  2274.       return 1;
  2275.     }
  2276.   LOG(llevError,"Error: LIFESAVE set without applied object.\n");
  2277.   CLEAR_FLAG(op, FLAG_LIFESAVE);
  2278.   return 0;
  2279. }
  2280.  
  2281. /* This goes throws the inventory and removes unpaid objects, and puts them
  2282.  * back in the map (location and map determined by values of env).  This
  2283.  * function will descend into containers.  op is the object to start the search
  2284.  * from.
  2285.  */
  2286. void remove_unpaid_objects(object *op, object *env)
  2287. {
  2288.     object *next;
  2289.  
  2290.     while (op) {
  2291.     next=op->below;    /* Make sure we have a good value, in case 
  2292.              * we remove object 'op'
  2293.              */
  2294.     if (QUERY_FLAG(op, FLAG_UNPAID)) {
  2295.         remove_ob(op);
  2296.         op->x = env->x;
  2297.         op->y = env->y;
  2298.         insert_ob_in_map(op, env->map);
  2299.     }
  2300.     else if (op->inv) remove_unpaid_objects(op->inv, env);
  2301.     op=next;
  2302.     }
  2303. }
  2304.  
  2305.  
  2306. void do_some_living(object *op) {
  2307.   char buf[MAX_BUF];
  2308.   object *tmp;
  2309.   int last_food=op->stats.food;
  2310.   int gen_hp, gen_sp, gen_grace;
  2311.   int x,y,i;  /*  these are for resurrection */
  2312.   mapstruct *map;  /*  this is for resurrection */
  2313.  
  2314.   if (op->contr->outputs_sync) {
  2315.     for (i=0; i<NUM_OUTPUT_BUFS; i++)
  2316.       if (op->contr->outputs[i].buf!=NULL &&
  2317.     (op->contr->outputs[i].first_update+op->contr->outputs_sync)<pticks)
  2318.         flush_output_element(op, &op->contr->outputs[i]);
  2319.   }
  2320.  
  2321.   if(op->contr->state==ST_PLAYING) {
  2322.     gen_hp=(op->contr->gen_hp+1)*op->stats.maxhp;
  2323.     gen_sp=(op->contr->gen_sp+1)*op->stats.maxsp;
  2324.      gen_grace=(op->contr->gen_grace+1)*op->stats.maxgrace;
  2325.     if(op->contr->golem==NULL&&--op->last_sp<0) {
  2326.          if(op->stats.sp<op->stats.maxsp)
  2327.              op->stats.sp++,op->stats.food--;
  2328.          op->last_sp=2000/(gen_sp<20 ? 30 : gen_sp+10);
  2329.          for(tmp=op->inv;tmp!=NULL;tmp=tmp->below)
  2330.              if((tmp->type==ARMOUR||tmp->type==HELMET||tmp->type==BOOTS||
  2331.                   tmp->type==SHIELD||tmp->type==GLOVES||tmp->type==GIRDLE||
  2332.                   tmp->type==AMULET)
  2333.                  &&QUERY_FLAG(tmp, FLAG_APPLIED))
  2334.                  op->last_sp+=ARMOUR_SPELLS(tmp);
  2335.     }
  2336.  
  2337.      /* regenerate grace */
  2338.     /* I altered this a little - maximum grace is ony achieved through prayer -b.t.*/
  2339.      if(--op->last_grace<0) {
  2340. #ifndef ALLOW_SKILLS /* allow regen 'naturally' to only 1/2 maxgrace w/ skills code */ 
  2341.          if(op->stats.grace<op->stats.maxgrace) 
  2342. #else
  2343.          if(op->stats.grace<op->stats.maxgrace/2)
  2344. #endif
  2345.              op->stats.grace++;  /* no penalty in food for regaining grace */
  2346.          op->last_grace=2500/(gen_grace<20? 30:gen_grace+10);
  2347.          /* wearing stuff doesn't detract from grace generation. */
  2348.      }
  2349.  
  2350.     if(--op->last_heal<0) {
  2351.          if(op->stats.hp<op->stats.maxhp)
  2352.              op->stats.hp++,op->stats.food--;
  2353.          op->last_heal=1200/(gen_hp<20 ? 30 : gen_hp+10);
  2354.          if(op->contr->digestion<0)
  2355.              op->stats.food+=op->contr->digestion;
  2356.          else if(op->contr->digestion>0&&RANDOM()%(1+op->contr->digestion))
  2357.              op->stats.food=last_food;
  2358.     }
  2359.     if(--op->last_eat<0) {
  2360.          int bonus=op->contr->digestion>0?op->contr->digestion:0,
  2361.          penalty=op->contr->digestion<0?-op->contr->digestion:0;
  2362.  
  2363.          op->last_eat=25*(1+bonus)/(op->contr->gen_hp+penalty+1);
  2364.          op->stats.food--;
  2365.     }
  2366.  }
  2367.   if(op->contr->state==ST_PLAYING&&op->stats.food<0&&op->stats.hp>=0) {
  2368.       object *tmp;
  2369.       for(tmp=op->inv;tmp!=NULL;tmp=tmp->below)
  2370.           if(!QUERY_FLAG(tmp, FLAG_UNPAID)&&
  2371.               (tmp->type==FOOD||tmp->type==DRINK||tmp->type==POISON))
  2372.               {
  2373.         new_draw_info(NDI_UNIQUE, 0,op,"You blindly grab for a bite of food.");
  2374.     apply(op,tmp);
  2375.     if(op->stats.food>=0||op->stats.hp<0)
  2376.       break;
  2377.       }
  2378.   }
  2379.   while(op->stats.food<0&&op->stats.hp>0)
  2380.     op->stats.food++,op->stats.hp--;
  2381.  
  2382.   if (!op->contr->state&&!QUERY_FLAG(op,FLAG_WIZ)&&(op->stats.hp<0||op->stats.food<0)) {
  2383.     if(save_life(op))
  2384.       return;
  2385.     if(op->stats.food<0) {
  2386. #ifdef EXPLORE_MODE
  2387.       if (op->contr->explore) {
  2388.       new_draw_info(NDI_UNIQUE, 0,op,"You would have starved, but you are");
  2389.       new_draw_info(NDI_UNIQUE, 0,op,"in explore mode, so...");
  2390.       op->stats.food=999;
  2391.       return;
  2392.       }
  2393. #endif /* EXPLORE_MODE */
  2394.       sprintf(buf,"%s starved to death.",op->name);
  2395.       strcpy(op->contr->killer,"starvation");
  2396.     }
  2397.     else
  2398. #ifdef EXPLORE_MODE
  2399.       if (op->contr->explore) {
  2400.       new_draw_info(NDI_UNIQUE, 0,op,"You would have died, but you are");
  2401.       new_draw_info(NDI_UNIQUE, 0,op,"in explore mode, so...");
  2402.       op->stats.hp=op->stats.maxhp;
  2403.       return;
  2404.       }
  2405. #endif /* EXPLORE_MODE */
  2406.       sprintf(buf,"%s died.",op->name);
  2407. #ifdef SOUND_EFFECTS
  2408.       play_sound_player_only(op->contr, SOUND_PLAYER_DIES);
  2409. #endif
  2410.     /*  save the map location for corpse, gravestone*/
  2411.     x=op->x;y=op->y;map=op->map;
  2412.  
  2413.  
  2414. #ifdef NOT_PERMADEATH
  2415. /****************************************************************************/
  2416. /* Patch: NOT_PERMADEATH                Author: Charles Henrich             */
  2417. /* Email: henrich@crh.cl.msu.edu        Date  : April 9, 1993               */
  2418. /*                                                                          */
  2419. /* Purpose: This patch changes death from being a permanent, very painful   */
  2420. /*          thing, to a painful, but survivable thing.  More mudlike in     */
  2421. /*          nature.  With this patch defined, when a player dies, they will */
  2422. /*          permanently lose one point off of a random stat, as well as     */
  2423. /*          losing 20% of their experience points.  Then they are whisked   */
  2424. /*          to the start map.  Although this sounds very nice here, it is   */
  2425. /*          still REAL painful to die, 20% of a million is alot!            */
  2426. /*                                                                          */
  2427. /****************************************************************************/
  2428.  
  2429.  /**************************************/
  2430.  /*                                    */
  2431.  /* Pick a stat, and steal on pt from  */
  2432.  /* it...                              */
  2433.  /*                                    */
  2434.  /**************************************/
  2435.     i = RANDOM() % 7;
  2436.     change_attr_value(&(op->stats), i,-1);
  2437.     check_stat_bounds(&(op->stats));
  2438.     change_attr_value(&(op->contr->orig_stats), i,-1);
  2439.     check_stat_bounds(&(op->contr->orig_stats));
  2440.     new_draw_info(NDI_UNIQUE, 0,op, lose_msg[i]);
  2441.  
  2442.  
  2443.  /**************************************/
  2444.  /*                                    */
  2445.  /* Lets make up a gravestone to put   */
  2446.  /* here... We put experience lost on  */
  2447.  /* it for kicks....                   */
  2448.  /*                                    */
  2449.  /**************************************/
  2450.  
  2451.     tmp=arch_to_object(find_archetype("gravestone"));
  2452.     sprintf(buf,"%s's gravestone",op->name);
  2453.     tmp->name=add_string(buf);
  2454.     sprintf(buf,"RIP\nHere rests the hero %s the %s,\n"
  2455.             "who lost %d experience when killed\n"
  2456.             "by %s.\n",
  2457.             op->name, op->contr->title, (int)(op->stats.exp * 0.20),
  2458.             op->contr->killer);
  2459.     tmp->msg = add_string(buf);
  2460.     tmp->x=op->x,tmp->y=op->y;
  2461.     insert_ob_in_map(tmp,op->map);
  2462.  
  2463.  /**************************************/
  2464.  /*                                    */
  2465.  /* Subtract the experience points,    */
  2466.  /* if we died cause of food, give us  */
  2467.  /* food, and reset HP's...            */
  2468.  /*                                    */
  2469.  /**************************************/
  2470.  
  2471.     /* remove any poisoning and confusion the character may be suffering. */
  2472.     cast_heal(op, 0, SP_CURE_POISON);
  2473.     cast_heal(op, 0, SP_CURE_CONFUSION);
  2474.     
  2475.     add_exp(op, (op->stats.exp * -0.20));
  2476.     if(op->stats.food < 0) op->stats.food = 500;
  2477.     op->stats.hp = op->stats.maxhp;
  2478.  
  2479.  /*
  2480.   * Check to see if the player is in a shop.  IF so, then check to see if
  2481.   * the player has any unpaid items.  If so, remove them and put them back
  2482.   * in the map.
  2483.   */
  2484.  
  2485.     tmp= get_map_ob(op->map, op->x, op->y);
  2486.     if (tmp && tmp->type == SHOP_FLOOR) {
  2487.     remove_unpaid_objects(op->inv, op);
  2488.     }
  2489.  
  2490.  
  2491.  /**************************************/
  2492.  /*                                    */
  2493.  /* Move the player to the beginning   */
  2494.  /* map....                            */
  2495.  /*                                    */
  2496.  /**************************************/
  2497.  
  2498.     tmp=get_object();
  2499.  
  2500.     EXIT_PATH(tmp) = add_string(first_map_path);
  2501.     enter_exit(op,tmp);
  2502.  
  2503. /* commenting this out seems to fix core dumps on some systems. */
  2504.     free_object(tmp);
  2505.  
  2506.  /**************************************/
  2507.  /*                                    */
  2508.  /* Repaint the characters inv, and    */
  2509.  /* stats, and show a nasty message ;) */
  2510.  /*                                    */
  2511.  /**************************************/
  2512.  
  2513.     draw_stats(op);
  2514. /*  draw_inventory(op);   inventory hasn't changed */
  2515.     new_draw_info(NDI_UNIQUE, 0,op,"YOU HAVE DIED.");
  2516.     save_player(op,1);
  2517.     return;
  2518. #endif
  2519.  
  2520. /* If NOT_PERMADETH is set, then the rest of this is not reachable.  This
  2521.  * should probably be embedded in an else statement.
  2522.  */
  2523.  
  2524. #ifdef SIMPLE_PARTY_SYSTEM
  2525.     op->contr->party_number=(-1);
  2526. #endif /* SIMPLE_PARTY_SYSTEM */
  2527. #ifdef SET_TITLE
  2528.     op->contr->own_title[0]='\0';
  2529. #endif /* SET_TITLE */
  2530.     op->contr->count_left=0;
  2531.     load_default_keys(op->contr);
  2532.     new_draw_info(NDI_UNIQUE|NDI_ALL, 0,NULL, buf);
  2533.     check_score(op);
  2534.     if(op->contr->golem!=NULL) {
  2535.       remove_friendly_object(op->contr->golem);
  2536.       remove_ob(op->contr->golem);
  2537.       free_object(op->contr->golem);
  2538.       op->contr->golem=NULL;
  2539.     }
  2540.     op->contr->freeze_inv=1;
  2541.     op->contr->freeze_look=1;
  2542.     loot_object(op); /* Remove some of the items for good */
  2543.     op->contr->freeze_inv=0;
  2544.     op->contr->freeze_look=0;
  2545.     remove_ob(op);
  2546.     op->direction=0;
  2547.     if(!QUERY_FLAG(op,FLAG_WAS_WIZ)&&op->stats.exp) {
  2548.       delete_character(op->name);
  2549. #ifndef NOT_PERMADEATH
  2550. #ifdef RESURRECTION
  2551.     /* save playerfile sans equipment when player dies
  2552.     ** then save it as player.pl.dead so that future resurrection
  2553.     ** type spells will work on them nicely
  2554.     */
  2555.     op->stats.hp = op->stats.maxhp;
  2556.     op->stats.food = 999;
  2557.  
  2558.     /*  set the location of where the person will reappear when  */
  2559.     /* maybe resurrection code should fix map also */
  2560.     strcpy(op->contr->maplevel, EMERGENCY_MAPPATH);
  2561.     if(op->map!=NULL)
  2562.         op->map = NULL;
  2563.     op->x = EMERGENCY_X;
  2564.     op->y = EMERGENCY_Y;
  2565.     save_player(op,0);
  2566.     op->map = map;
  2567.     /* please see resurrection.c: peterm */
  2568.     dead_player(op);
  2569. #endif
  2570. #endif
  2571.     }
  2572.     play_again(op);
  2573. #ifdef NOT_PERMADEATH
  2574.     tmp=arch_to_object(find_archetype("gravestone"));
  2575.     sprintf(buf,"%s's gravestone",op->name);
  2576.     tmp->name=add_string(buf);
  2577.     sprintf(buf,"RIP\nHere rests the hero %s the %s,\nwho was killed by %s.\n",
  2578.         op->name, op->contr->title, op->contr->killer);
  2579.     tmp->msg = add_string(buf);
  2580.     tmp->x=x,tmp->y=y;
  2581.     insert_ob_in_map(tmp,map);
  2582. #else
  2583.     /*  peterm:  added to create a corpse at deathsite.  */
  2584.     tmp=arch_to_object(find_archetype("corpse_pl"));
  2585.     sprintf(buf,"%s", op->name);
  2586.     if (tmp->name)
  2587.     free_string (tmp->name);
  2588.     tmp->name=add_string(buf);
  2589.     tmp->level=op->level;
  2590.     tmp->x=x;tmp->y=y;
  2591.     if (tmp->msg)
  2592.     free_string(tmp->msg);
  2593.     tmp->msg = gravestone_text(op);
  2594.     SET_FLAG (tmp, FLAG_UNIQUE);
  2595.     insert_ob_in_map(tmp,map);
  2596. #endif
  2597.   }
  2598. }
  2599.  
  2600. void loot_object(object *op) { /* Grab and destroy some treasure */
  2601.   object *tmp,*tmp2,*next;
  2602.  
  2603.   if (op->container) { /* close open sack first */
  2604.     if (op->contr->eric_server > 0)
  2605.       esrv_apply_container (op, op->container);
  2606.     else
  2607.       apply_container (op, op->container);
  2608.   }
  2609.  
  2610.   for(tmp=op->inv;tmp!=NULL;tmp=next) {
  2611.     next=tmp->below;
  2612.     remove_ob(tmp);
  2613.     tmp->x=op->x,tmp->y=op->y;
  2614.     if (tmp->type == CONTAINER) { /* empty container to ground */
  2615.     loot_object(tmp);
  2616.     }
  2617.     if(!QUERY_FLAG(tmp, FLAG_UNIQUE) && (QUERY_FLAG(tmp, FLAG_STARTEQUIP) 
  2618.        || QUERY_FLAG(tmp,FLAG_NO_DROP) || !(RANDOM()%3))) {
  2619.       if(tmp->nrof>1) {
  2620.     tmp2=get_split_ob(tmp,1+RANDOM()%(tmp->nrof-1));
  2621.     free_object(tmp2);
  2622.     insert_ob_in_map(tmp,op->map);
  2623.       } else
  2624.     free_object(tmp);
  2625.     } else
  2626.       insert_ob_in_map(tmp,op->map);
  2627.   }
  2628. }
  2629.  
  2630. /*
  2631.  * fix_weight(): Check recursively the weight of all players, and fix
  2632.  * what needs to be fixed.  Refresh windows and fix speed if anything
  2633.  * was changed.
  2634.  */
  2635.  
  2636. void fix_weight() {
  2637.   player *pl;
  2638.   for (pl = first_player; pl != NULL; pl = pl->next) {
  2639.     int old = pl->ob->carrying, sum = sum_weight(pl->ob);
  2640.     if(old == sum)
  2641.       continue;
  2642.     fix_player(pl->ob);
  2643.     draw_inventory(pl->ob);
  2644.     LOG(llevDebug,"Fixed inventory in %s (%d -> %d)\n",
  2645.     pl->ob->name, old, sum);
  2646.   }
  2647. }
  2648.  
  2649. void fix_luck() {
  2650.   player *pl;
  2651.   for (pl = first_player; pl != NULL; pl = pl->next)
  2652.     if (!pl->ob->contr->state)
  2653.       change_luck(pl->ob, 0);
  2654. }
  2655.  
  2656.  
  2657. void client_speed(long cid)
  2658. {
  2659.   player *pl;
  2660.   for(pl=first_player;pl != NULL; pl = pl->next)
  2661.     if (pl->eric_server == cid)
  2662.       printf("speed left = %.2f\n",pl->ob->speed_left);
  2663. }
  2664.